xref: /openbmc/linux/tools/lib/bpf/usdt.bpf.h (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1d72e2968SAndrii Nakryiko /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2d72e2968SAndrii Nakryiko /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3d72e2968SAndrii Nakryiko #ifndef __USDT_BPF_H__
4d72e2968SAndrii Nakryiko #define __USDT_BPF_H__
5d72e2968SAndrii Nakryiko 
6d72e2968SAndrii Nakryiko #include <linux/errno.h>
7*dde3979bSSergey Kacheev #include "bpf_helpers.h"
8*dde3979bSSergey Kacheev #include "bpf_tracing.h"
9d72e2968SAndrii Nakryiko 
10d72e2968SAndrii Nakryiko /* Below types and maps are internal implementation details of libbpf's USDT
11d72e2968SAndrii Nakryiko  * support and are subjects to change. Also, bpf_usdt_xxx() API helpers should
12d72e2968SAndrii Nakryiko  * be considered an unstable API as well and might be adjusted based on user
13d72e2968SAndrii Nakryiko  * feedback from using libbpf's USDT support in production.
14d72e2968SAndrii Nakryiko  */
15d72e2968SAndrii Nakryiko 
16d72e2968SAndrii Nakryiko /* User can override BPF_USDT_MAX_SPEC_CNT to change default size of internal
17d72e2968SAndrii Nakryiko  * map that keeps track of USDT argument specifications. This might be
18d72e2968SAndrii Nakryiko  * necessary if there are a lot of USDT attachments.
19d72e2968SAndrii Nakryiko  */
20d72e2968SAndrii Nakryiko #ifndef BPF_USDT_MAX_SPEC_CNT
21d72e2968SAndrii Nakryiko #define BPF_USDT_MAX_SPEC_CNT 256
22d72e2968SAndrii Nakryiko #endif
23d72e2968SAndrii Nakryiko /* User can override BPF_USDT_MAX_IP_CNT to change default size of internal
24d72e2968SAndrii Nakryiko  * map that keeps track of IP (memory address) mapping to USDT argument
25d72e2968SAndrii Nakryiko  * specification.
26d72e2968SAndrii Nakryiko  * Note, if kernel supports BPF cookies, this map is not used and could be
27d72e2968SAndrii Nakryiko  * resized all the way to 1 to save a bit of memory.
28d72e2968SAndrii Nakryiko  */
29d72e2968SAndrii Nakryiko #ifndef BPF_USDT_MAX_IP_CNT
30d72e2968SAndrii Nakryiko #define BPF_USDT_MAX_IP_CNT (4 * BPF_USDT_MAX_SPEC_CNT)
31d72e2968SAndrii Nakryiko #endif
32d72e2968SAndrii Nakryiko 
33d72e2968SAndrii Nakryiko enum __bpf_usdt_arg_type {
34d72e2968SAndrii Nakryiko 	BPF_USDT_ARG_CONST,
35d72e2968SAndrii Nakryiko 	BPF_USDT_ARG_REG,
36d72e2968SAndrii Nakryiko 	BPF_USDT_ARG_REG_DEREF,
37d72e2968SAndrii Nakryiko };
38d72e2968SAndrii Nakryiko 
39d72e2968SAndrii Nakryiko struct __bpf_usdt_arg_spec {
40d72e2968SAndrii Nakryiko 	/* u64 scalar interpreted depending on arg_type, see below */
41d72e2968SAndrii Nakryiko 	__u64 val_off;
42d72e2968SAndrii Nakryiko 	/* arg location case, see bpf_udst_arg() for details */
43d72e2968SAndrii Nakryiko 	enum __bpf_usdt_arg_type arg_type;
44d72e2968SAndrii Nakryiko 	/* offset of referenced register within struct pt_regs */
45d72e2968SAndrii Nakryiko 	short reg_off;
46d72e2968SAndrii Nakryiko 	/* whether arg should be interpreted as signed value */
47d72e2968SAndrii Nakryiko 	bool arg_signed;
48d72e2968SAndrii Nakryiko 	/* number of bits that need to be cleared and, optionally,
49d72e2968SAndrii Nakryiko 	 * sign-extended to cast arguments that are 1, 2, or 4 bytes
50d72e2968SAndrii Nakryiko 	 * long into final 8-byte u64/s64 value returned to user
51d72e2968SAndrii Nakryiko 	 */
52d72e2968SAndrii Nakryiko 	char arg_bitshift;
53d72e2968SAndrii Nakryiko };
54d72e2968SAndrii Nakryiko 
55d72e2968SAndrii Nakryiko /* should match USDT_MAX_ARG_CNT in usdt.c exactly */
56d72e2968SAndrii Nakryiko #define BPF_USDT_MAX_ARG_CNT 12
57d72e2968SAndrii Nakryiko struct __bpf_usdt_spec {
58d72e2968SAndrii Nakryiko 	struct __bpf_usdt_arg_spec args[BPF_USDT_MAX_ARG_CNT];
59d72e2968SAndrii Nakryiko 	__u64 usdt_cookie;
60d72e2968SAndrii Nakryiko 	short arg_cnt;
61d72e2968SAndrii Nakryiko };
62d72e2968SAndrii Nakryiko 
63d72e2968SAndrii Nakryiko struct {
64d72e2968SAndrii Nakryiko 	__uint(type, BPF_MAP_TYPE_ARRAY);
65d72e2968SAndrii Nakryiko 	__uint(max_entries, BPF_USDT_MAX_SPEC_CNT);
66d72e2968SAndrii Nakryiko 	__type(key, int);
67d72e2968SAndrii Nakryiko 	__type(value, struct __bpf_usdt_spec);
68d72e2968SAndrii Nakryiko } __bpf_usdt_specs SEC(".maps") __weak;
69d72e2968SAndrii Nakryiko 
70d72e2968SAndrii Nakryiko struct {
71d72e2968SAndrii Nakryiko 	__uint(type, BPF_MAP_TYPE_HASH);
72d72e2968SAndrii Nakryiko 	__uint(max_entries, BPF_USDT_MAX_IP_CNT);
73d72e2968SAndrii Nakryiko 	__type(key, long);
74d72e2968SAndrii Nakryiko 	__type(value, __u32);
75d72e2968SAndrii Nakryiko } __bpf_usdt_ip_to_spec_id SEC(".maps") __weak;
76d72e2968SAndrii Nakryiko 
7755d00c37SAndrii Nakryiko extern const _Bool LINUX_HAS_BPF_COOKIE __kconfig;
78d72e2968SAndrii Nakryiko 
79d72e2968SAndrii Nakryiko static __always_inline
__bpf_usdt_spec_id(struct pt_regs * ctx)80d72e2968SAndrii Nakryiko int __bpf_usdt_spec_id(struct pt_regs *ctx)
81d72e2968SAndrii Nakryiko {
8255d00c37SAndrii Nakryiko 	if (!LINUX_HAS_BPF_COOKIE) {
83d72e2968SAndrii Nakryiko 		long ip = PT_REGS_IP(ctx);
84d72e2968SAndrii Nakryiko 		int *spec_id_ptr;
85d72e2968SAndrii Nakryiko 
86d72e2968SAndrii Nakryiko 		spec_id_ptr = bpf_map_lookup_elem(&__bpf_usdt_ip_to_spec_id, &ip);
87d72e2968SAndrii Nakryiko 		return spec_id_ptr ? *spec_id_ptr : -ESRCH;
88d72e2968SAndrii Nakryiko 	}
89d72e2968SAndrii Nakryiko 
90d72e2968SAndrii Nakryiko 	return bpf_get_attach_cookie(ctx);
91d72e2968SAndrii Nakryiko }
92d72e2968SAndrii Nakryiko 
93d72e2968SAndrii Nakryiko /* Return number of USDT arguments defined for currently traced USDT. */
942fa5b0f2SAndrii Nakryiko __weak __hidden
bpf_usdt_arg_cnt(struct pt_regs * ctx)95d72e2968SAndrii Nakryiko int bpf_usdt_arg_cnt(struct pt_regs *ctx)
96d72e2968SAndrii Nakryiko {
97d72e2968SAndrii Nakryiko 	struct __bpf_usdt_spec *spec;
98d72e2968SAndrii Nakryiko 	int spec_id;
99d72e2968SAndrii Nakryiko 
100d72e2968SAndrii Nakryiko 	spec_id = __bpf_usdt_spec_id(ctx);
101d72e2968SAndrii Nakryiko 	if (spec_id < 0)
102d72e2968SAndrii Nakryiko 		return -ESRCH;
103d72e2968SAndrii Nakryiko 
104d72e2968SAndrii Nakryiko 	spec = bpf_map_lookup_elem(&__bpf_usdt_specs, &spec_id);
105d72e2968SAndrii Nakryiko 	if (!spec)
106d72e2968SAndrii Nakryiko 		return -ESRCH;
107d72e2968SAndrii Nakryiko 
108d72e2968SAndrii Nakryiko 	return spec->arg_cnt;
109d72e2968SAndrii Nakryiko }
110d72e2968SAndrii Nakryiko 
111d72e2968SAndrii Nakryiko /* Fetch USDT argument #*arg_num* (zero-indexed) and put its value into *res.
112d72e2968SAndrii Nakryiko  * Returns 0 on success; negative error, otherwise.
113d72e2968SAndrii Nakryiko  * On error *res is guaranteed to be set to zero.
114d72e2968SAndrii Nakryiko  */
1152fa5b0f2SAndrii Nakryiko __weak __hidden
bpf_usdt_arg(struct pt_regs * ctx,__u64 arg_num,long * res)116d72e2968SAndrii Nakryiko int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res)
117d72e2968SAndrii Nakryiko {
118d72e2968SAndrii Nakryiko 	struct __bpf_usdt_spec *spec;
119d72e2968SAndrii Nakryiko 	struct __bpf_usdt_arg_spec *arg_spec;
120d72e2968SAndrii Nakryiko 	unsigned long val;
121d72e2968SAndrii Nakryiko 	int err, spec_id;
122d72e2968SAndrii Nakryiko 
123d72e2968SAndrii Nakryiko 	*res = 0;
124d72e2968SAndrii Nakryiko 
125d72e2968SAndrii Nakryiko 	spec_id = __bpf_usdt_spec_id(ctx);
126d72e2968SAndrii Nakryiko 	if (spec_id < 0)
127d72e2968SAndrii Nakryiko 		return -ESRCH;
128d72e2968SAndrii Nakryiko 
129d72e2968SAndrii Nakryiko 	spec = bpf_map_lookup_elem(&__bpf_usdt_specs, &spec_id);
130d72e2968SAndrii Nakryiko 	if (!spec)
131d72e2968SAndrii Nakryiko 		return -ESRCH;
132d72e2968SAndrii Nakryiko 
13325c76ed4SIlya Leoshkevich 	if (arg_num >= BPF_USDT_MAX_ARG_CNT)
13425c76ed4SIlya Leoshkevich 		return -ENOENT;
13525c76ed4SIlya Leoshkevich 	barrier_var(arg_num);
13625c76ed4SIlya Leoshkevich 	if (arg_num >= spec->arg_cnt)
137d72e2968SAndrii Nakryiko 		return -ENOENT;
138d72e2968SAndrii Nakryiko 
139d72e2968SAndrii Nakryiko 	arg_spec = &spec->args[arg_num];
140d72e2968SAndrii Nakryiko 	switch (arg_spec->arg_type) {
141d72e2968SAndrii Nakryiko 	case BPF_USDT_ARG_CONST:
142d72e2968SAndrii Nakryiko 		/* Arg is just a constant ("-4@$-9" in USDT arg spec).
143d72e2968SAndrii Nakryiko 		 * value is recorded in arg_spec->val_off directly.
144d72e2968SAndrii Nakryiko 		 */
145d72e2968SAndrii Nakryiko 		val = arg_spec->val_off;
146d72e2968SAndrii Nakryiko 		break;
147d72e2968SAndrii Nakryiko 	case BPF_USDT_ARG_REG:
148d72e2968SAndrii Nakryiko 		/* Arg is in a register (e.g, "8@%rax" in USDT arg spec),
149d72e2968SAndrii Nakryiko 		 * so we read the contents of that register directly from
150d72e2968SAndrii Nakryiko 		 * struct pt_regs. To keep things simple user-space parts
151d72e2968SAndrii Nakryiko 		 * record offsetof(struct pt_regs, <regname>) in arg_spec->reg_off.
152d72e2968SAndrii Nakryiko 		 */
153d72e2968SAndrii Nakryiko 		err = bpf_probe_read_kernel(&val, sizeof(val), (void *)ctx + arg_spec->reg_off);
154d72e2968SAndrii Nakryiko 		if (err)
155d72e2968SAndrii Nakryiko 			return err;
156d72e2968SAndrii Nakryiko 		break;
157d72e2968SAndrii Nakryiko 	case BPF_USDT_ARG_REG_DEREF:
158d72e2968SAndrii Nakryiko 		/* Arg is in memory addressed by register, plus some offset
159d72e2968SAndrii Nakryiko 		 * (e.g., "-4@-1204(%rbp)" in USDT arg spec). Register is
160e1b6df59SIlya Leoshkevich 		 * identified like with BPF_USDT_ARG_REG case, and the offset
161d72e2968SAndrii Nakryiko 		 * is in arg_spec->val_off. We first fetch register contents
162d72e2968SAndrii Nakryiko 		 * from pt_regs, then do another user-space probe read to
163d72e2968SAndrii Nakryiko 		 * fetch argument value itself.
164d72e2968SAndrii Nakryiko 		 */
165d72e2968SAndrii Nakryiko 		err = bpf_probe_read_kernel(&val, sizeof(val), (void *)ctx + arg_spec->reg_off);
166d72e2968SAndrii Nakryiko 		if (err)
167d72e2968SAndrii Nakryiko 			return err;
168d72e2968SAndrii Nakryiko 		err = bpf_probe_read_user(&val, sizeof(val), (void *)val + arg_spec->val_off);
169d72e2968SAndrii Nakryiko 		if (err)
170d72e2968SAndrii Nakryiko 			return err;
1716f403d9dSIlya Leoshkevich #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1726f403d9dSIlya Leoshkevich 		val >>= arg_spec->arg_bitshift;
1736f403d9dSIlya Leoshkevich #endif
174d72e2968SAndrii Nakryiko 		break;
175d72e2968SAndrii Nakryiko 	default:
176d72e2968SAndrii Nakryiko 		return -EINVAL;
177d72e2968SAndrii Nakryiko 	}
178d72e2968SAndrii Nakryiko 
179d72e2968SAndrii Nakryiko 	/* cast arg from 1, 2, or 4 bytes to final 8 byte size clearing
180d72e2968SAndrii Nakryiko 	 * necessary upper arg_bitshift bits, with sign extension if argument
181d72e2968SAndrii Nakryiko 	 * is signed
182d72e2968SAndrii Nakryiko 	 */
183d72e2968SAndrii Nakryiko 	val <<= arg_spec->arg_bitshift;
184d72e2968SAndrii Nakryiko 	if (arg_spec->arg_signed)
185d72e2968SAndrii Nakryiko 		val = ((long)val) >> arg_spec->arg_bitshift;
186d72e2968SAndrii Nakryiko 	else
187d72e2968SAndrii Nakryiko 		val = val >> arg_spec->arg_bitshift;
188d72e2968SAndrii Nakryiko 	*res = val;
189d72e2968SAndrii Nakryiko 	return 0;
190d72e2968SAndrii Nakryiko }
191d72e2968SAndrii Nakryiko 
192d72e2968SAndrii Nakryiko /* Retrieve user-specified cookie value provided during attach as
193d72e2968SAndrii Nakryiko  * bpf_usdt_opts.usdt_cookie. This serves the same purpose as BPF cookie
194d72e2968SAndrii Nakryiko  * returned by bpf_get_attach_cookie(). Libbpf's support for USDT is itself
195e1b6df59SIlya Leoshkevich  * utilizing BPF cookies internally, so user can't use BPF cookie directly
196d72e2968SAndrii Nakryiko  * for USDT programs and has to use bpf_usdt_cookie() API instead.
197d72e2968SAndrii Nakryiko  */
1982fa5b0f2SAndrii Nakryiko __weak __hidden
bpf_usdt_cookie(struct pt_regs * ctx)199d72e2968SAndrii Nakryiko long bpf_usdt_cookie(struct pt_regs *ctx)
200d72e2968SAndrii Nakryiko {
201d72e2968SAndrii Nakryiko 	struct __bpf_usdt_spec *spec;
202d72e2968SAndrii Nakryiko 	int spec_id;
203d72e2968SAndrii Nakryiko 
204d72e2968SAndrii Nakryiko 	spec_id = __bpf_usdt_spec_id(ctx);
205d72e2968SAndrii Nakryiko 	if (spec_id < 0)
206d72e2968SAndrii Nakryiko 		return 0;
207d72e2968SAndrii Nakryiko 
208d72e2968SAndrii Nakryiko 	spec = bpf_map_lookup_elem(&__bpf_usdt_specs, &spec_id);
209d72e2968SAndrii Nakryiko 	if (!spec)
210d72e2968SAndrii Nakryiko 		return 0;
211d72e2968SAndrii Nakryiko 
212d72e2968SAndrii Nakryiko 	return spec->usdt_cookie;
213d72e2968SAndrii Nakryiko }
214d72e2968SAndrii Nakryiko 
215d72e2968SAndrii Nakryiko /* we rely on ___bpf_apply() and ___bpf_narg() macros already defined in bpf_tracing.h */
216d72e2968SAndrii Nakryiko #define ___bpf_usdt_args0() ctx
217d72e2968SAndrii Nakryiko #define ___bpf_usdt_args1(x) ___bpf_usdt_args0(), ({ long _x; bpf_usdt_arg(ctx, 0, &_x); (void *)_x; })
218d72e2968SAndrii Nakryiko #define ___bpf_usdt_args2(x, args...) ___bpf_usdt_args1(args), ({ long _x; bpf_usdt_arg(ctx, 1, &_x); (void *)_x; })
219d72e2968SAndrii Nakryiko #define ___bpf_usdt_args3(x, args...) ___bpf_usdt_args2(args), ({ long _x; bpf_usdt_arg(ctx, 2, &_x); (void *)_x; })
220d72e2968SAndrii Nakryiko #define ___bpf_usdt_args4(x, args...) ___bpf_usdt_args3(args), ({ long _x; bpf_usdt_arg(ctx, 3, &_x); (void *)_x; })
221d72e2968SAndrii Nakryiko #define ___bpf_usdt_args5(x, args...) ___bpf_usdt_args4(args), ({ long _x; bpf_usdt_arg(ctx, 4, &_x); (void *)_x; })
222d72e2968SAndrii Nakryiko #define ___bpf_usdt_args6(x, args...) ___bpf_usdt_args5(args), ({ long _x; bpf_usdt_arg(ctx, 5, &_x); (void *)_x; })
223d72e2968SAndrii Nakryiko #define ___bpf_usdt_args7(x, args...) ___bpf_usdt_args6(args), ({ long _x; bpf_usdt_arg(ctx, 6, &_x); (void *)_x; })
224d72e2968SAndrii Nakryiko #define ___bpf_usdt_args8(x, args...) ___bpf_usdt_args7(args), ({ long _x; bpf_usdt_arg(ctx, 7, &_x); (void *)_x; })
225d72e2968SAndrii Nakryiko #define ___bpf_usdt_args9(x, args...) ___bpf_usdt_args8(args), ({ long _x; bpf_usdt_arg(ctx, 8, &_x); (void *)_x; })
226d72e2968SAndrii Nakryiko #define ___bpf_usdt_args10(x, args...) ___bpf_usdt_args9(args), ({ long _x; bpf_usdt_arg(ctx, 9, &_x); (void *)_x; })
227d72e2968SAndrii Nakryiko #define ___bpf_usdt_args11(x, args...) ___bpf_usdt_args10(args), ({ long _x; bpf_usdt_arg(ctx, 10, &_x); (void *)_x; })
228d72e2968SAndrii Nakryiko #define ___bpf_usdt_args12(x, args...) ___bpf_usdt_args11(args), ({ long _x; bpf_usdt_arg(ctx, 11, &_x); (void *)_x; })
229d72e2968SAndrii Nakryiko #define ___bpf_usdt_args(args...) ___bpf_apply(___bpf_usdt_args, ___bpf_narg(args))(args)
230d72e2968SAndrii Nakryiko 
231d72e2968SAndrii Nakryiko /*
232d72e2968SAndrii Nakryiko  * BPF_USDT serves the same purpose for USDT handlers as BPF_PROG for
233d72e2968SAndrii Nakryiko  * tp_btf/fentry/fexit BPF programs and BPF_KPROBE for kprobes.
234d72e2968SAndrii Nakryiko  * Original struct pt_regs * context is preserved as 'ctx' argument.
235d72e2968SAndrii Nakryiko  */
236d72e2968SAndrii Nakryiko #define BPF_USDT(name, args...)						    \
237d72e2968SAndrii Nakryiko name(struct pt_regs *ctx);						    \
238d25f40ffSJames Hilliard static __always_inline typeof(name(0))					    \
239d72e2968SAndrii Nakryiko ____##name(struct pt_regs *ctx, ##args);				    \
240d72e2968SAndrii Nakryiko typeof(name(0)) name(struct pt_regs *ctx)				    \
241d72e2968SAndrii Nakryiko {									    \
242d72e2968SAndrii Nakryiko         _Pragma("GCC diagnostic push")					    \
243d72e2968SAndrii Nakryiko         _Pragma("GCC diagnostic ignored \"-Wint-conversion\"")		    \
244d72e2968SAndrii Nakryiko         return ____##name(___bpf_usdt_args(args));			    \
245d72e2968SAndrii Nakryiko         _Pragma("GCC diagnostic pop")					    \
246d72e2968SAndrii Nakryiko }									    \
247d25f40ffSJames Hilliard static __always_inline typeof(name(0))					    \
248d72e2968SAndrii Nakryiko ____##name(struct pt_regs *ctx, ##args)
249d72e2968SAndrii Nakryiko 
250d72e2968SAndrii Nakryiko #endif /* __USDT_BPF_H__ */
251