xref: /aosp_15_r20/external/bcc/libbpf-tools/ksnoop.bpf.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2*387f9dfdSAndroid Build Coastguard Worker /* Copyright (c) 2021, Oracle and/or its affiliates. */
3*387f9dfdSAndroid Build Coastguard Worker 
4*387f9dfdSAndroid Build Coastguard Worker #include "vmlinux.h"
5*387f9dfdSAndroid Build Coastguard Worker 
6*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_helpers.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_tracing.h>
8*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_core_read.h>
9*387f9dfdSAndroid Build Coastguard Worker 
10*387f9dfdSAndroid Build Coastguard Worker #include "ksnoop.h"
11*387f9dfdSAndroid Build Coastguard Worker 
12*387f9dfdSAndroid Build Coastguard Worker /* For kretprobes, the instruction pointer in the struct pt_regs context
13*387f9dfdSAndroid Build Coastguard Worker  * is the kretprobe_trampoline.  We derive the instruction pointer
14*387f9dfdSAndroid Build Coastguard Worker  * by pushing it onto a function stack on entry and popping it on return.
15*387f9dfdSAndroid Build Coastguard Worker  *
16*387f9dfdSAndroid Build Coastguard Worker  * We could use bpf_get_func_ip(), but "stack mode" - where we
17*387f9dfdSAndroid Build Coastguard Worker  * specify functions "a", "b and "c" and only want to see a trace if "a"
18*387f9dfdSAndroid Build Coastguard Worker  * calls "b" and "b" calls "c" - utilizes this stack to determine if trace
19*387f9dfdSAndroid Build Coastguard Worker  * data should be collected.
20*387f9dfdSAndroid Build Coastguard Worker  */
21*387f9dfdSAndroid Build Coastguard Worker #define FUNC_MAX_STACK_DEPTH	16
22*387f9dfdSAndroid Build Coastguard Worker /* used to convince verifier we do not stray outside of array bounds */
23*387f9dfdSAndroid Build Coastguard Worker #define FUNC_STACK_DEPTH_MASK	(FUNC_MAX_STACK_DEPTH - 1)
24*387f9dfdSAndroid Build Coastguard Worker 
25*387f9dfdSAndroid Build Coastguard Worker #ifndef ENOSPC
26*387f9dfdSAndroid Build Coastguard Worker #define ENOSPC			28
27*387f9dfdSAndroid Build Coastguard Worker #endif
28*387f9dfdSAndroid Build Coastguard Worker 
29*387f9dfdSAndroid Build Coastguard Worker struct func_stack {
30*387f9dfdSAndroid Build Coastguard Worker 	__u64 task;
31*387f9dfdSAndroid Build Coastguard Worker 	__u64 ips[FUNC_MAX_STACK_DEPTH];
32*387f9dfdSAndroid Build Coastguard Worker 	__u8 stack_depth;
33*387f9dfdSAndroid Build Coastguard Worker };
34*387f9dfdSAndroid Build Coastguard Worker 
35*387f9dfdSAndroid Build Coastguard Worker #define MAX_TASKS		2048
36*387f9dfdSAndroid Build Coastguard Worker 
37*387f9dfdSAndroid Build Coastguard Worker /* function call stack hashed on a per-task key */
38*387f9dfdSAndroid Build Coastguard Worker struct {
39*387f9dfdSAndroid Build Coastguard Worker 	__uint(type, BPF_MAP_TYPE_HASH);
40*387f9dfdSAndroid Build Coastguard Worker 	/* function call stack for functions we are tracing */
41*387f9dfdSAndroid Build Coastguard Worker 	__uint(max_entries, MAX_TASKS);
42*387f9dfdSAndroid Build Coastguard Worker 	__type(key, __u64);
43*387f9dfdSAndroid Build Coastguard Worker 	__type(value, struct func_stack);
44*387f9dfdSAndroid Build Coastguard Worker } ksnoop_func_stack SEC(".maps");
45*387f9dfdSAndroid Build Coastguard Worker 
46*387f9dfdSAndroid Build Coastguard Worker /* per-cpu trace info hashed on function address */
47*387f9dfdSAndroid Build Coastguard Worker struct {
48*387f9dfdSAndroid Build Coastguard Worker 	__uint(type, BPF_MAP_TYPE_PERCPU_HASH);
49*387f9dfdSAndroid Build Coastguard Worker 	__uint(max_entries, MAX_FUNC_TRACES);
50*387f9dfdSAndroid Build Coastguard Worker 	__type(key, __u64);
51*387f9dfdSAndroid Build Coastguard Worker 	__type(value, struct trace);
52*387f9dfdSAndroid Build Coastguard Worker } ksnoop_func_map SEC(".maps");
53*387f9dfdSAndroid Build Coastguard Worker 
54*387f9dfdSAndroid Build Coastguard Worker struct {
55*387f9dfdSAndroid Build Coastguard Worker 	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
56*387f9dfdSAndroid Build Coastguard Worker 	__uint(value_size, sizeof(int));
57*387f9dfdSAndroid Build Coastguard Worker 	__uint(key_size, sizeof(int));
58*387f9dfdSAndroid Build Coastguard Worker } ksnoop_perf_map SEC(".maps");
59*387f9dfdSAndroid Build Coastguard Worker 
clear_trace(struct trace * trace)60*387f9dfdSAndroid Build Coastguard Worker static void clear_trace(struct trace *trace)
61*387f9dfdSAndroid Build Coastguard Worker {
62*387f9dfdSAndroid Build Coastguard Worker 	__builtin_memset(&trace->trace_data, 0, sizeof(trace->trace_data));
63*387f9dfdSAndroid Build Coastguard Worker 	trace->data_flags = 0;
64*387f9dfdSAndroid Build Coastguard Worker 	trace->buf_len = 0;
65*387f9dfdSAndroid Build Coastguard Worker }
66*387f9dfdSAndroid Build Coastguard Worker 
get_trace(struct pt_regs * ctx,bool entry)67*387f9dfdSAndroid Build Coastguard Worker static struct trace *get_trace(struct pt_regs *ctx, bool entry)
68*387f9dfdSAndroid Build Coastguard Worker {
69*387f9dfdSAndroid Build Coastguard Worker 	__u8 stack_depth, last_stack_depth;
70*387f9dfdSAndroid Build Coastguard Worker 	struct func_stack *func_stack;
71*387f9dfdSAndroid Build Coastguard Worker 	__u64 ip, last_ip = 0, task;
72*387f9dfdSAndroid Build Coastguard Worker 	struct trace *trace;
73*387f9dfdSAndroid Build Coastguard Worker 
74*387f9dfdSAndroid Build Coastguard Worker 	task = bpf_get_current_task();
75*387f9dfdSAndroid Build Coastguard Worker 
76*387f9dfdSAndroid Build Coastguard Worker 	func_stack = bpf_map_lookup_elem(&ksnoop_func_stack, &task);
77*387f9dfdSAndroid Build Coastguard Worker 	if (!func_stack) {
78*387f9dfdSAndroid Build Coastguard Worker 		struct func_stack new_stack = { .task = task };
79*387f9dfdSAndroid Build Coastguard Worker 
80*387f9dfdSAndroid Build Coastguard Worker 		bpf_map_update_elem(&ksnoop_func_stack, &task, &new_stack,
81*387f9dfdSAndroid Build Coastguard Worker 				    BPF_NOEXIST);
82*387f9dfdSAndroid Build Coastguard Worker 		func_stack = bpf_map_lookup_elem(&ksnoop_func_stack, &task);
83*387f9dfdSAndroid Build Coastguard Worker 		if (!func_stack)
84*387f9dfdSAndroid Build Coastguard Worker 			return NULL;
85*387f9dfdSAndroid Build Coastguard Worker 	}
86*387f9dfdSAndroid Build Coastguard Worker 
87*387f9dfdSAndroid Build Coastguard Worker 	stack_depth = func_stack->stack_depth;
88*387f9dfdSAndroid Build Coastguard Worker 	if (stack_depth > FUNC_MAX_STACK_DEPTH)
89*387f9dfdSAndroid Build Coastguard Worker 		return NULL;
90*387f9dfdSAndroid Build Coastguard Worker 
91*387f9dfdSAndroid Build Coastguard Worker 	if (entry) {
92*387f9dfdSAndroid Build Coastguard Worker 		if (bpf_core_enum_value_exists(enum bpf_func_id,
93*387f9dfdSAndroid Build Coastguard Worker 					       BPF_FUNC_get_func_ip))
94*387f9dfdSAndroid Build Coastguard Worker 			ip = bpf_get_func_ip(ctx);
95*387f9dfdSAndroid Build Coastguard Worker 		else
96*387f9dfdSAndroid Build Coastguard Worker 			ip = KSNOOP_IP_FIX(PT_REGS_IP_CORE(ctx));
97*387f9dfdSAndroid Build Coastguard Worker 		if (stack_depth >= FUNC_MAX_STACK_DEPTH - 1)
98*387f9dfdSAndroid Build Coastguard Worker 			return NULL;
99*387f9dfdSAndroid Build Coastguard Worker 		/* verifier doesn't like using "stack_depth - 1" as array index
100*387f9dfdSAndroid Build Coastguard Worker 		 * directly.
101*387f9dfdSAndroid Build Coastguard Worker 		 */
102*387f9dfdSAndroid Build Coastguard Worker 		last_stack_depth = stack_depth - 1;
103*387f9dfdSAndroid Build Coastguard Worker 		/* get address of last function we called */
104*387f9dfdSAndroid Build Coastguard Worker 		if (last_stack_depth >= 0 &&
105*387f9dfdSAndroid Build Coastguard Worker 		    last_stack_depth < FUNC_MAX_STACK_DEPTH)
106*387f9dfdSAndroid Build Coastguard Worker 			last_ip = func_stack->ips[last_stack_depth];
107*387f9dfdSAndroid Build Coastguard Worker 		/* push ip onto stack. return will pop it. */
108*387f9dfdSAndroid Build Coastguard Worker 		func_stack->ips[stack_depth] = ip;
109*387f9dfdSAndroid Build Coastguard Worker 		/* mask used in case bounds checks are optimized out */
110*387f9dfdSAndroid Build Coastguard Worker 		stack_depth = (stack_depth + 1) & FUNC_STACK_DEPTH_MASK;
111*387f9dfdSAndroid Build Coastguard Worker 		func_stack->stack_depth = stack_depth;
112*387f9dfdSAndroid Build Coastguard Worker 		/* rather than zero stack entries on popping, we zero the
113*387f9dfdSAndroid Build Coastguard Worker 		 * (stack_depth + 1)'th entry when pushing the current
114*387f9dfdSAndroid Build Coastguard Worker 		 * entry.  The reason we take this approach is that
115*387f9dfdSAndroid Build Coastguard Worker 		 * when tracking the set of functions we returned from,
116*387f9dfdSAndroid Build Coastguard Worker 		 * we want the history of functions we returned from to
117*387f9dfdSAndroid Build Coastguard Worker 		 * be preserved.
118*387f9dfdSAndroid Build Coastguard Worker 		 */
119*387f9dfdSAndroid Build Coastguard Worker 		if (stack_depth < FUNC_MAX_STACK_DEPTH)
120*387f9dfdSAndroid Build Coastguard Worker 			func_stack->ips[stack_depth] = 0;
121*387f9dfdSAndroid Build Coastguard Worker 	} else {
122*387f9dfdSAndroid Build Coastguard Worker 		if (stack_depth == 0 || stack_depth >= FUNC_MAX_STACK_DEPTH)
123*387f9dfdSAndroid Build Coastguard Worker 			return NULL;
124*387f9dfdSAndroid Build Coastguard Worker 		last_stack_depth = stack_depth;
125*387f9dfdSAndroid Build Coastguard Worker 		/* get address of last function we returned from */
126*387f9dfdSAndroid Build Coastguard Worker 		if (last_stack_depth >= 0 &&
127*387f9dfdSAndroid Build Coastguard Worker 		    last_stack_depth < FUNC_MAX_STACK_DEPTH)
128*387f9dfdSAndroid Build Coastguard Worker 			last_ip = func_stack->ips[last_stack_depth];
129*387f9dfdSAndroid Build Coastguard Worker 		if (stack_depth > 0) {
130*387f9dfdSAndroid Build Coastguard Worker 			/* logical OR convinces verifier that we don't
131*387f9dfdSAndroid Build Coastguard Worker 			 * end up with a < 0 value, translating to 0xff
132*387f9dfdSAndroid Build Coastguard Worker 			 * and an outside of map element access.
133*387f9dfdSAndroid Build Coastguard Worker 			 */
134*387f9dfdSAndroid Build Coastguard Worker 			stack_depth = (stack_depth - 1) & FUNC_STACK_DEPTH_MASK;
135*387f9dfdSAndroid Build Coastguard Worker 		}
136*387f9dfdSAndroid Build Coastguard Worker 		/* retrieve ip from stack as IP in pt_regs is
137*387f9dfdSAndroid Build Coastguard Worker 		 * bpf kretprobe trampoline address.
138*387f9dfdSAndroid Build Coastguard Worker 		 */
139*387f9dfdSAndroid Build Coastguard Worker 		if (stack_depth >= 0 && stack_depth < FUNC_MAX_STACK_DEPTH)
140*387f9dfdSAndroid Build Coastguard Worker 			ip = func_stack->ips[stack_depth];
141*387f9dfdSAndroid Build Coastguard Worker 		if (stack_depth >= 0 && stack_depth < FUNC_MAX_STACK_DEPTH)
142*387f9dfdSAndroid Build Coastguard Worker 			func_stack->stack_depth = stack_depth;
143*387f9dfdSAndroid Build Coastguard Worker 	}
144*387f9dfdSAndroid Build Coastguard Worker 
145*387f9dfdSAndroid Build Coastguard Worker 	trace = bpf_map_lookup_elem(&ksnoop_func_map, &ip);
146*387f9dfdSAndroid Build Coastguard Worker 	if (!trace)
147*387f9dfdSAndroid Build Coastguard Worker 		return NULL;
148*387f9dfdSAndroid Build Coastguard Worker 
149*387f9dfdSAndroid Build Coastguard Worker 	/* we may stash data on entry since predicates are a mix
150*387f9dfdSAndroid Build Coastguard Worker 	 * of entry/return; in such cases, trace->flags specifies
151*387f9dfdSAndroid Build Coastguard Worker 	 * KSNOOP_F_STASH, and we will output stashed data on return.
152*387f9dfdSAndroid Build Coastguard Worker 	 * If returning, make sure we don't clear our stashed data.
153*387f9dfdSAndroid Build Coastguard Worker 	 */
154*387f9dfdSAndroid Build Coastguard Worker 	if (!entry && (trace->flags & KSNOOP_F_STASH)) {
155*387f9dfdSAndroid Build Coastguard Worker 		/* skip clearing trace data */
156*387f9dfdSAndroid Build Coastguard Worker 		if (!(trace->data_flags & KSNOOP_F_STASHED)) {
157*387f9dfdSAndroid Build Coastguard Worker 			/* predicate must have failed */
158*387f9dfdSAndroid Build Coastguard Worker 			return NULL;
159*387f9dfdSAndroid Build Coastguard Worker 		}
160*387f9dfdSAndroid Build Coastguard Worker 		/* skip clearing trace data */
161*387f9dfdSAndroid Build Coastguard Worker 	} else {
162*387f9dfdSAndroid Build Coastguard Worker 		/* clear trace data before starting. */
163*387f9dfdSAndroid Build Coastguard Worker 		clear_trace(trace);
164*387f9dfdSAndroid Build Coastguard Worker 	}
165*387f9dfdSAndroid Build Coastguard Worker 
166*387f9dfdSAndroid Build Coastguard Worker 	if (entry) {
167*387f9dfdSAndroid Build Coastguard Worker 		/* if in stack mode, check if previous fn matches */
168*387f9dfdSAndroid Build Coastguard Worker 		if (trace->prev_ip && trace->prev_ip != last_ip)
169*387f9dfdSAndroid Build Coastguard Worker 			return NULL;
170*387f9dfdSAndroid Build Coastguard Worker 		/* if tracing intermediate fn in stack of fns, stash data. */
171*387f9dfdSAndroid Build Coastguard Worker 		if (trace->next_ip)
172*387f9dfdSAndroid Build Coastguard Worker 			trace->data_flags |= KSNOOP_F_STASH;
173*387f9dfdSAndroid Build Coastguard Worker 		/* we may stash data on entry since predicates are a mix
174*387f9dfdSAndroid Build Coastguard Worker 		 * of entry/return; in such cases, trace->flags specifies
175*387f9dfdSAndroid Build Coastguard Worker 		 * KSNOOP_F_STASH, and we will output stashed data on return.
176*387f9dfdSAndroid Build Coastguard Worker 		 */
177*387f9dfdSAndroid Build Coastguard Worker 		if (trace->flags & KSNOOP_F_STASH)
178*387f9dfdSAndroid Build Coastguard Worker 			trace->data_flags |= KSNOOP_F_STASH;
179*387f9dfdSAndroid Build Coastguard Worker 		/* otherwise the data is outputted (because we've reached
180*387f9dfdSAndroid Build Coastguard Worker 		 * the last fn in the set of fns specified).
181*387f9dfdSAndroid Build Coastguard Worker 		 */
182*387f9dfdSAndroid Build Coastguard Worker 	} else {
183*387f9dfdSAndroid Build Coastguard Worker 		/* In stack mode, check if next fn matches the last fn
184*387f9dfdSAndroid Build Coastguard Worker 		 * we returned from; i.e. "a" called "b", and now
185*387f9dfdSAndroid Build Coastguard Worker 		 * we're at "a", was the last fn we returned from "b"?
186*387f9dfdSAndroid Build Coastguard Worker 		 * If so, stash data for later display (when we reach the
187*387f9dfdSAndroid Build Coastguard Worker 		 * first fn in the set of stack fns).
188*387f9dfdSAndroid Build Coastguard Worker 		 */
189*387f9dfdSAndroid Build Coastguard Worker 		if (trace->next_ip && trace->next_ip != last_ip)
190*387f9dfdSAndroid Build Coastguard Worker 			return NULL;
191*387f9dfdSAndroid Build Coastguard Worker 		if (trace->prev_ip)
192*387f9dfdSAndroid Build Coastguard Worker 			trace->data_flags |= KSNOOP_F_STASH;
193*387f9dfdSAndroid Build Coastguard Worker 		/* If there is no "prev" function, i.e. we are at the
194*387f9dfdSAndroid Build Coastguard Worker 		 * first function in a set of stack functions, the trace
195*387f9dfdSAndroid Build Coastguard Worker 		 * info is shown (along with any stashed info associated
196*387f9dfdSAndroid Build Coastguard Worker 		 * with callers).
197*387f9dfdSAndroid Build Coastguard Worker 		 */
198*387f9dfdSAndroid Build Coastguard Worker 	}
199*387f9dfdSAndroid Build Coastguard Worker 	trace->task = task;
200*387f9dfdSAndroid Build Coastguard Worker 	return trace;
201*387f9dfdSAndroid Build Coastguard Worker }
202*387f9dfdSAndroid Build Coastguard Worker 
output_trace(struct pt_regs * ctx,struct trace * trace)203*387f9dfdSAndroid Build Coastguard Worker static void output_trace(struct pt_regs *ctx, struct trace *trace)
204*387f9dfdSAndroid Build Coastguard Worker {
205*387f9dfdSAndroid Build Coastguard Worker 	__u16 trace_len;
206*387f9dfdSAndroid Build Coastguard Worker 
207*387f9dfdSAndroid Build Coastguard Worker 	if (trace->buf_len == 0)
208*387f9dfdSAndroid Build Coastguard Worker 		goto skip;
209*387f9dfdSAndroid Build Coastguard Worker 
210*387f9dfdSAndroid Build Coastguard Worker 	/* we may be simply stashing values, and will report later */
211*387f9dfdSAndroid Build Coastguard Worker 	if (trace->data_flags & KSNOOP_F_STASH) {
212*387f9dfdSAndroid Build Coastguard Worker 		trace->data_flags &= ~KSNOOP_F_STASH;
213*387f9dfdSAndroid Build Coastguard Worker 		trace->data_flags |= KSNOOP_F_STASHED;
214*387f9dfdSAndroid Build Coastguard Worker 		return;
215*387f9dfdSAndroid Build Coastguard Worker 	}
216*387f9dfdSAndroid Build Coastguard Worker 	/* we may be outputting earlier stashed data */
217*387f9dfdSAndroid Build Coastguard Worker 	if (trace->data_flags & KSNOOP_F_STASHED)
218*387f9dfdSAndroid Build Coastguard Worker 		trace->data_flags &= ~KSNOOP_F_STASHED;
219*387f9dfdSAndroid Build Coastguard Worker 
220*387f9dfdSAndroid Build Coastguard Worker 	/* trim perf event size to only contain data we've recorded. */
221*387f9dfdSAndroid Build Coastguard Worker 	trace_len = sizeof(*trace) + trace->buf_len - MAX_TRACE_BUF;
222*387f9dfdSAndroid Build Coastguard Worker 
223*387f9dfdSAndroid Build Coastguard Worker 	if (trace_len <= sizeof(*trace))
224*387f9dfdSAndroid Build Coastguard Worker 		bpf_perf_event_output(ctx, &ksnoop_perf_map,
225*387f9dfdSAndroid Build Coastguard Worker 				      BPF_F_CURRENT_CPU,
226*387f9dfdSAndroid Build Coastguard Worker 				      trace, trace_len);
227*387f9dfdSAndroid Build Coastguard Worker skip:
228*387f9dfdSAndroid Build Coastguard Worker 	clear_trace(trace);
229*387f9dfdSAndroid Build Coastguard Worker }
230*387f9dfdSAndroid Build Coastguard Worker 
output_stashed_traces(struct pt_regs * ctx,struct trace * currtrace,bool entry)231*387f9dfdSAndroid Build Coastguard Worker static void output_stashed_traces(struct pt_regs *ctx,
232*387f9dfdSAndroid Build Coastguard Worker 					 struct trace *currtrace,
233*387f9dfdSAndroid Build Coastguard Worker 					 bool entry)
234*387f9dfdSAndroid Build Coastguard Worker {
235*387f9dfdSAndroid Build Coastguard Worker 	struct func_stack *func_stack;
236*387f9dfdSAndroid Build Coastguard Worker 	struct trace *trace = NULL;
237*387f9dfdSAndroid Build Coastguard Worker 	__u8 i;
238*387f9dfdSAndroid Build Coastguard Worker 	__u64 task = 0;
239*387f9dfdSAndroid Build Coastguard Worker 
240*387f9dfdSAndroid Build Coastguard Worker 	task = bpf_get_current_task();
241*387f9dfdSAndroid Build Coastguard Worker 	func_stack = bpf_map_lookup_elem(&ksnoop_func_stack, &task);
242*387f9dfdSAndroid Build Coastguard Worker 	if (!func_stack)
243*387f9dfdSAndroid Build Coastguard Worker 		return;
244*387f9dfdSAndroid Build Coastguard Worker 
245*387f9dfdSAndroid Build Coastguard Worker 	if (entry) {
246*387f9dfdSAndroid Build Coastguard Worker 		/* iterate from bottom to top of stack, outputting stashed
247*387f9dfdSAndroid Build Coastguard Worker 		 * data we find.  This corresponds to the set of functions
248*387f9dfdSAndroid Build Coastguard Worker 		 * we called before the current function.
249*387f9dfdSAndroid Build Coastguard Worker 		 */
250*387f9dfdSAndroid Build Coastguard Worker 		for (i = 0;
251*387f9dfdSAndroid Build Coastguard Worker 		     i < func_stack->stack_depth - 1 && i < FUNC_MAX_STACK_DEPTH;
252*387f9dfdSAndroid Build Coastguard Worker 		     i++) {
253*387f9dfdSAndroid Build Coastguard Worker 			trace = bpf_map_lookup_elem(&ksnoop_func_map,
254*387f9dfdSAndroid Build Coastguard Worker 						    &func_stack->ips[i]);
255*387f9dfdSAndroid Build Coastguard Worker 			if (!trace || !(trace->data_flags & KSNOOP_F_STASHED))
256*387f9dfdSAndroid Build Coastguard Worker 				break;
257*387f9dfdSAndroid Build Coastguard Worker 			if (trace->task != task)
258*387f9dfdSAndroid Build Coastguard Worker 				return;
259*387f9dfdSAndroid Build Coastguard Worker 			output_trace(ctx, trace);
260*387f9dfdSAndroid Build Coastguard Worker 		}
261*387f9dfdSAndroid Build Coastguard Worker 	} else {
262*387f9dfdSAndroid Build Coastguard Worker 		/* iterate from top to bottom of stack, outputting stashed
263*387f9dfdSAndroid Build Coastguard Worker 		 * data we find.  This corresponds to the set of functions
264*387f9dfdSAndroid Build Coastguard Worker 		 * that returned prior to the current returning function.
265*387f9dfdSAndroid Build Coastguard Worker 		 */
266*387f9dfdSAndroid Build Coastguard Worker 		for (i = FUNC_MAX_STACK_DEPTH; i > 0; i--) {
267*387f9dfdSAndroid Build Coastguard Worker 			__u64 ip;
268*387f9dfdSAndroid Build Coastguard Worker 
269*387f9dfdSAndroid Build Coastguard Worker 			ip = func_stack->ips[i];
270*387f9dfdSAndroid Build Coastguard Worker 			if (!ip)
271*387f9dfdSAndroid Build Coastguard Worker 				continue;
272*387f9dfdSAndroid Build Coastguard Worker 			trace = bpf_map_lookup_elem(&ksnoop_func_map, &ip);
273*387f9dfdSAndroid Build Coastguard Worker 			if (!trace || !(trace->data_flags & KSNOOP_F_STASHED))
274*387f9dfdSAndroid Build Coastguard Worker 				break;
275*387f9dfdSAndroid Build Coastguard Worker 			if (trace->task != task)
276*387f9dfdSAndroid Build Coastguard Worker 				return;
277*387f9dfdSAndroid Build Coastguard Worker 			output_trace(ctx, trace);
278*387f9dfdSAndroid Build Coastguard Worker 		}
279*387f9dfdSAndroid Build Coastguard Worker 	}
280*387f9dfdSAndroid Build Coastguard Worker 	/* finally output the current trace info */
281*387f9dfdSAndroid Build Coastguard Worker 	output_trace(ctx, currtrace);
282*387f9dfdSAndroid Build Coastguard Worker }
283*387f9dfdSAndroid Build Coastguard Worker 
get_arg(struct pt_regs * ctx,enum arg argnum)284*387f9dfdSAndroid Build Coastguard Worker static __u64 get_arg(struct pt_regs *ctx, enum arg argnum)
285*387f9dfdSAndroid Build Coastguard Worker {
286*387f9dfdSAndroid Build Coastguard Worker 	switch (argnum) {
287*387f9dfdSAndroid Build Coastguard Worker 	case KSNOOP_ARG1:
288*387f9dfdSAndroid Build Coastguard Worker 		return PT_REGS_PARM1_CORE(ctx);
289*387f9dfdSAndroid Build Coastguard Worker 	case KSNOOP_ARG2:
290*387f9dfdSAndroid Build Coastguard Worker 		return PT_REGS_PARM2_CORE(ctx);
291*387f9dfdSAndroid Build Coastguard Worker 	case KSNOOP_ARG3:
292*387f9dfdSAndroid Build Coastguard Worker 		return PT_REGS_PARM3_CORE(ctx);
293*387f9dfdSAndroid Build Coastguard Worker 	case KSNOOP_ARG4:
294*387f9dfdSAndroid Build Coastguard Worker 		return PT_REGS_PARM4_CORE(ctx);
295*387f9dfdSAndroid Build Coastguard Worker 	case KSNOOP_ARG5:
296*387f9dfdSAndroid Build Coastguard Worker 		return PT_REGS_PARM5_CORE(ctx);
297*387f9dfdSAndroid Build Coastguard Worker 	case KSNOOP_RETURN:
298*387f9dfdSAndroid Build Coastguard Worker 		return PT_REGS_RC_CORE(ctx);
299*387f9dfdSAndroid Build Coastguard Worker 	default:
300*387f9dfdSAndroid Build Coastguard Worker 		return 0;
301*387f9dfdSAndroid Build Coastguard Worker 	}
302*387f9dfdSAndroid Build Coastguard Worker }
303*387f9dfdSAndroid Build Coastguard Worker 
ksnoop(struct pt_regs * ctx,bool entry)304*387f9dfdSAndroid Build Coastguard Worker static int ksnoop(struct pt_regs *ctx, bool entry)
305*387f9dfdSAndroid Build Coastguard Worker {
306*387f9dfdSAndroid Build Coastguard Worker 	void *data_ptr = NULL;
307*387f9dfdSAndroid Build Coastguard Worker 	struct trace *trace;
308*387f9dfdSAndroid Build Coastguard Worker 	__u64 data;
309*387f9dfdSAndroid Build Coastguard Worker 	__u32 currpid;
310*387f9dfdSAndroid Build Coastguard Worker 	int ret;
311*387f9dfdSAndroid Build Coastguard Worker 	__u8 i;
312*387f9dfdSAndroid Build Coastguard Worker 
313*387f9dfdSAndroid Build Coastguard Worker 	trace = get_trace(ctx, entry);
314*387f9dfdSAndroid Build Coastguard Worker 	if (!trace)
315*387f9dfdSAndroid Build Coastguard Worker 		return 0;
316*387f9dfdSAndroid Build Coastguard Worker 
317*387f9dfdSAndroid Build Coastguard Worker 	/* make sure we want events from this pid */
318*387f9dfdSAndroid Build Coastguard Worker 	currpid = bpf_get_current_pid_tgid();
319*387f9dfdSAndroid Build Coastguard Worker 	if (trace->filter_pid && trace->filter_pid != currpid)
320*387f9dfdSAndroid Build Coastguard Worker 		return 0;
321*387f9dfdSAndroid Build Coastguard Worker 	trace->pid = currpid;
322*387f9dfdSAndroid Build Coastguard Worker 
323*387f9dfdSAndroid Build Coastguard Worker 	trace->cpu = bpf_get_smp_processor_id();
324*387f9dfdSAndroid Build Coastguard Worker 	trace->time = bpf_ktime_get_ns();
325*387f9dfdSAndroid Build Coastguard Worker 
326*387f9dfdSAndroid Build Coastguard Worker 	trace->data_flags &= ~(KSNOOP_F_ENTRY | KSNOOP_F_RETURN);
327*387f9dfdSAndroid Build Coastguard Worker 	if (entry)
328*387f9dfdSAndroid Build Coastguard Worker 		trace->data_flags |= KSNOOP_F_ENTRY;
329*387f9dfdSAndroid Build Coastguard Worker 	else
330*387f9dfdSAndroid Build Coastguard Worker 		trace->data_flags |= KSNOOP_F_RETURN;
331*387f9dfdSAndroid Build Coastguard Worker 
332*387f9dfdSAndroid Build Coastguard Worker 
333*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < MAX_TRACES; i++) {
334*387f9dfdSAndroid Build Coastguard Worker 		struct trace_data *currdata;
335*387f9dfdSAndroid Build Coastguard Worker 		struct value *currtrace;
336*387f9dfdSAndroid Build Coastguard Worker 		char *buf_offset = NULL;
337*387f9dfdSAndroid Build Coastguard Worker 		__u32 tracesize;
338*387f9dfdSAndroid Build Coastguard Worker 
339*387f9dfdSAndroid Build Coastguard Worker 		currdata = &trace->trace_data[i];
340*387f9dfdSAndroid Build Coastguard Worker 		currtrace = &trace->traces[i];
341*387f9dfdSAndroid Build Coastguard Worker 
342*387f9dfdSAndroid Build Coastguard Worker 		if ((entry && !base_arg_is_entry(currtrace->base_arg)) ||
343*387f9dfdSAndroid Build Coastguard Worker 		    (!entry && base_arg_is_entry(currtrace->base_arg)))
344*387f9dfdSAndroid Build Coastguard Worker 			continue;
345*387f9dfdSAndroid Build Coastguard Worker 
346*387f9dfdSAndroid Build Coastguard Worker 		/* skip void (unused) trace arguments, ensuring not to
347*387f9dfdSAndroid Build Coastguard Worker 		 * skip "void *".
348*387f9dfdSAndroid Build Coastguard Worker 		 */
349*387f9dfdSAndroid Build Coastguard Worker 		if (currtrace->type_id == 0 &&
350*387f9dfdSAndroid Build Coastguard Worker 		    !(currtrace->flags & KSNOOP_F_PTR))
351*387f9dfdSAndroid Build Coastguard Worker 			continue;
352*387f9dfdSAndroid Build Coastguard Worker 
353*387f9dfdSAndroid Build Coastguard Worker 		data = get_arg(ctx, currtrace->base_arg);
354*387f9dfdSAndroid Build Coastguard Worker 
355*387f9dfdSAndroid Build Coastguard Worker 		/* look up member value and read into data field. */
356*387f9dfdSAndroid Build Coastguard Worker 		if (currtrace->flags & KSNOOP_F_MEMBER) {
357*387f9dfdSAndroid Build Coastguard Worker 			if (currtrace->offset)
358*387f9dfdSAndroid Build Coastguard Worker 				data += currtrace->offset;
359*387f9dfdSAndroid Build Coastguard Worker 
360*387f9dfdSAndroid Build Coastguard Worker 			/* member is a pointer; read it in */
361*387f9dfdSAndroid Build Coastguard Worker 			if (currtrace->flags & KSNOOP_F_PTR) {
362*387f9dfdSAndroid Build Coastguard Worker 				void *dataptr = (void *)data;
363*387f9dfdSAndroid Build Coastguard Worker 
364*387f9dfdSAndroid Build Coastguard Worker 				ret = bpf_probe_read_kernel(&data, sizeof(data), dataptr);
365*387f9dfdSAndroid Build Coastguard Worker 				if (ret) {
366*387f9dfdSAndroid Build Coastguard Worker 					currdata->err_type_id = currtrace->type_id;
367*387f9dfdSAndroid Build Coastguard Worker 					currdata->err = ret;
368*387f9dfdSAndroid Build Coastguard Worker 					continue;
369*387f9dfdSAndroid Build Coastguard Worker 				}
370*387f9dfdSAndroid Build Coastguard Worker 				currdata->raw_value = data;
371*387f9dfdSAndroid Build Coastguard Worker 			} else if (currtrace->size <=
372*387f9dfdSAndroid Build Coastguard Worker 				   sizeof(currdata->raw_value)) {
373*387f9dfdSAndroid Build Coastguard Worker 				/* read member value for predicate comparison */
374*387f9dfdSAndroid Build Coastguard Worker 				bpf_probe_read_kernel(&currdata->raw_value, currtrace->size, (void*)data);
375*387f9dfdSAndroid Build Coastguard Worker 			}
376*387f9dfdSAndroid Build Coastguard Worker 		} else {
377*387f9dfdSAndroid Build Coastguard Worker 			currdata->raw_value = data;
378*387f9dfdSAndroid Build Coastguard Worker 		}
379*387f9dfdSAndroid Build Coastguard Worker 
380*387f9dfdSAndroid Build Coastguard Worker 		/* simple predicate evaluation: if any predicate fails,
381*387f9dfdSAndroid Build Coastguard Worker 		 * skip all tracing for this function.
382*387f9dfdSAndroid Build Coastguard Worker 		 */
383*387f9dfdSAndroid Build Coastguard Worker 		if (currtrace->flags & KSNOOP_F_PREDICATE_MASK) {
384*387f9dfdSAndroid Build Coastguard Worker 			bool ok = false;
385*387f9dfdSAndroid Build Coastguard Worker 
386*387f9dfdSAndroid Build Coastguard Worker 			if (currtrace->flags & KSNOOP_F_PREDICATE_EQ &&
387*387f9dfdSAndroid Build Coastguard Worker 			    currdata->raw_value == currtrace->predicate_value)
388*387f9dfdSAndroid Build Coastguard Worker 				ok = true;
389*387f9dfdSAndroid Build Coastguard Worker 
390*387f9dfdSAndroid Build Coastguard Worker 			if (currtrace->flags & KSNOOP_F_PREDICATE_NOTEQ &&
391*387f9dfdSAndroid Build Coastguard Worker 			    currdata->raw_value != currtrace->predicate_value)
392*387f9dfdSAndroid Build Coastguard Worker 				ok = true;
393*387f9dfdSAndroid Build Coastguard Worker 
394*387f9dfdSAndroid Build Coastguard Worker 			if (currtrace->flags & KSNOOP_F_PREDICATE_GT &&
395*387f9dfdSAndroid Build Coastguard Worker 			    currdata->raw_value > currtrace->predicate_value)
396*387f9dfdSAndroid Build Coastguard Worker 				ok = true;
397*387f9dfdSAndroid Build Coastguard Worker 
398*387f9dfdSAndroid Build Coastguard Worker 			if (currtrace->flags & KSNOOP_F_PREDICATE_LT &&
399*387f9dfdSAndroid Build Coastguard Worker 			    currdata->raw_value < currtrace->predicate_value)
400*387f9dfdSAndroid Build Coastguard Worker 				ok = true;
401*387f9dfdSAndroid Build Coastguard Worker 
402*387f9dfdSAndroid Build Coastguard Worker 			if (!ok) {
403*387f9dfdSAndroid Build Coastguard Worker 				clear_trace(trace);
404*387f9dfdSAndroid Build Coastguard Worker 				return 0;
405*387f9dfdSAndroid Build Coastguard Worker 			}
406*387f9dfdSAndroid Build Coastguard Worker 		}
407*387f9dfdSAndroid Build Coastguard Worker 
408*387f9dfdSAndroid Build Coastguard Worker 		if (currtrace->flags & (KSNOOP_F_PTR | KSNOOP_F_MEMBER))
409*387f9dfdSAndroid Build Coastguard Worker 			data_ptr = (void *)data;
410*387f9dfdSAndroid Build Coastguard Worker 		else
411*387f9dfdSAndroid Build Coastguard Worker 			data_ptr = &data;
412*387f9dfdSAndroid Build Coastguard Worker 
413*387f9dfdSAndroid Build Coastguard Worker 		if (trace->buf_len + MAX_TRACE_DATA >= MAX_TRACE_BUF)
414*387f9dfdSAndroid Build Coastguard Worker 			break;
415*387f9dfdSAndroid Build Coastguard Worker 
416*387f9dfdSAndroid Build Coastguard Worker 		buf_offset = &trace->buf[trace->buf_len];
417*387f9dfdSAndroid Build Coastguard Worker 		if (buf_offset > &trace->buf[MAX_TRACE_BUF]) {
418*387f9dfdSAndroid Build Coastguard Worker 			currdata->err_type_id = currtrace->type_id;
419*387f9dfdSAndroid Build Coastguard Worker 			currdata->err = -ENOSPC;
420*387f9dfdSAndroid Build Coastguard Worker 			continue;
421*387f9dfdSAndroid Build Coastguard Worker 		}
422*387f9dfdSAndroid Build Coastguard Worker 		currdata->buf_offset = trace->buf_len;
423*387f9dfdSAndroid Build Coastguard Worker 
424*387f9dfdSAndroid Build Coastguard Worker 		tracesize = currtrace->size;
425*387f9dfdSAndroid Build Coastguard Worker 		if (tracesize > MAX_TRACE_DATA)
426*387f9dfdSAndroid Build Coastguard Worker 			tracesize = MAX_TRACE_DATA;
427*387f9dfdSAndroid Build Coastguard Worker 		ret = bpf_probe_read_kernel(buf_offset, tracesize, data_ptr);
428*387f9dfdSAndroid Build Coastguard Worker 		if (ret < 0) {
429*387f9dfdSAndroid Build Coastguard Worker 			currdata->err_type_id = currtrace->type_id;
430*387f9dfdSAndroid Build Coastguard Worker 			currdata->err = ret;
431*387f9dfdSAndroid Build Coastguard Worker 			continue;
432*387f9dfdSAndroid Build Coastguard Worker 		} else {
433*387f9dfdSAndroid Build Coastguard Worker 			currdata->buf_len = tracesize;
434*387f9dfdSAndroid Build Coastguard Worker 			trace->buf_len += tracesize;
435*387f9dfdSAndroid Build Coastguard Worker 		}
436*387f9dfdSAndroid Build Coastguard Worker 	}
437*387f9dfdSAndroid Build Coastguard Worker 
438*387f9dfdSAndroid Build Coastguard Worker 	/* show accumulated stashed traces (if any) */
439*387f9dfdSAndroid Build Coastguard Worker 	if ((entry && trace->prev_ip && !trace->next_ip) ||
440*387f9dfdSAndroid Build Coastguard Worker 	    (!entry && trace->next_ip && !trace->prev_ip))
441*387f9dfdSAndroid Build Coastguard Worker 		output_stashed_traces(ctx, trace, entry);
442*387f9dfdSAndroid Build Coastguard Worker 	else
443*387f9dfdSAndroid Build Coastguard Worker 		output_trace(ctx, trace);
444*387f9dfdSAndroid Build Coastguard Worker 
445*387f9dfdSAndroid Build Coastguard Worker 	return 0;
446*387f9dfdSAndroid Build Coastguard Worker }
447*387f9dfdSAndroid Build Coastguard Worker 
448*387f9dfdSAndroid Build Coastguard Worker SEC("kprobe/foo")
BPF_KPROBE(kprobe_entry)449*387f9dfdSAndroid Build Coastguard Worker int BPF_KPROBE(kprobe_entry)
450*387f9dfdSAndroid Build Coastguard Worker {
451*387f9dfdSAndroid Build Coastguard Worker 	return ksnoop(ctx, true);
452*387f9dfdSAndroid Build Coastguard Worker }
453*387f9dfdSAndroid Build Coastguard Worker 
454*387f9dfdSAndroid Build Coastguard Worker SEC("kretprobe/foo")
BPF_KRETPROBE(kprobe_return)455*387f9dfdSAndroid Build Coastguard Worker int BPF_KRETPROBE(kprobe_return)
456*387f9dfdSAndroid Build Coastguard Worker {
457*387f9dfdSAndroid Build Coastguard Worker 	return ksnoop(ctx, false);
458*387f9dfdSAndroid Build Coastguard Worker }
459*387f9dfdSAndroid Build Coastguard Worker 
460*387f9dfdSAndroid Build Coastguard Worker char _license[] SEC("license") = "Dual BSD/GPL";
461