xref: /linux/tools/testing/selftests/bpf/usdt.h (revision e4dcbdff114e2c0a8059c396e233aa5d9637afce)
1*17c3b001SJiri Olsa // SPDX-License-Identifier: BSD-2-Clause
2*17c3b001SJiri Olsa /*
3*17c3b001SJiri Olsa  *  This single-header library defines a collection of variadic macros for
4*17c3b001SJiri Olsa  *  defining and triggering USDTs (User Statically-Defined Tracepoints):
5*17c3b001SJiri Olsa  *
6*17c3b001SJiri Olsa  *      - For USDTs without associated semaphore:
7*17c3b001SJiri Olsa  *          USDT(group, name, args...)
8*17c3b001SJiri Olsa  *
9*17c3b001SJiri Olsa  *      - For USDTs with implicit (transparent to the user) semaphore:
10*17c3b001SJiri Olsa  *          USDT_WITH_SEMA(group, name, args...)
11*17c3b001SJiri Olsa  *          USDT_IS_ACTIVE(group, name)
12*17c3b001SJiri Olsa  *
13*17c3b001SJiri Olsa  *      - For USDTs with explicit (user-defined and provided) semaphore:
14*17c3b001SJiri Olsa  *          USDT_WITH_EXPLICIT_SEMA(sema, group, name, args...)
15*17c3b001SJiri Olsa  *          USDT_SEMA_IS_ACTIVE(sema)
16*17c3b001SJiri Olsa  *
17*17c3b001SJiri Olsa  *  all of which emit a NOP instruction into the instruction stream, and so
18*17c3b001SJiri Olsa  *  have *zero* overhead for the surrounding code. USDTs are identified by
19*17c3b001SJiri Olsa  *  a combination of `group` and `name` identifiers, which is used by external
20*17c3b001SJiri Olsa  *  tracing tooling (tracers) for identifying exact USDTs of interest.
21*17c3b001SJiri Olsa  *
22*17c3b001SJiri Olsa  *  USDTs can have an associated (2-byte) activity counter (USDT semaphore),
23*17c3b001SJiri Olsa  *  automatically maintained by Linux kernel whenever any correctly written
24*17c3b001SJiri Olsa  *  BPF-based tracer is attached to the USDT. This USDT semaphore can be used
25*17c3b001SJiri Olsa  *  to check whether there is a need to do any extra data collection and
26*17c3b001SJiri Olsa  *  processing for a given USDT (if necessary), and otherwise avoid extra work
27*17c3b001SJiri Olsa  *  for a common case of USDT not being traced ("active").
28*17c3b001SJiri Olsa  *
29*17c3b001SJiri Olsa  *  See documentation for USDT_WITH_SEMA()/USDT_IS_ACTIVE() or
30*17c3b001SJiri Olsa  *  USDT_WITH_EXPLICIT_SEMA()/USDT_SEMA_IS_ACTIVE() APIs below for details on
31*17c3b001SJiri Olsa  *  working with USDTs with implicitly or explicitly associated
32*17c3b001SJiri Olsa  *  USDT semaphores, respectively.
33*17c3b001SJiri Olsa  *
34*17c3b001SJiri Olsa  *  There is also some additional data recorded into an auxiliary note
35*17c3b001SJiri Olsa  *  section. The data in the note section describes the operands, in terms of
36*17c3b001SJiri Olsa  *  size and location, used by tracing tooling to know where to find USDT
37*17c3b001SJiri Olsa  *  arguments. Each location is encoded as an assembler operand string.
38*17c3b001SJiri Olsa  *  Tracing tools (bpftrace and BPF-based tracers, systemtap, etc) insert
39*17c3b001SJiri Olsa  *  breakpoints on top of the nop, and decode the location operand-strings,
40*17c3b001SJiri Olsa  *  like an assembler, to find the values being passed.
41*17c3b001SJiri Olsa  *
42*17c3b001SJiri Olsa  *  The operand strings are selected by the compiler for each operand.
43*17c3b001SJiri Olsa  *  They are constrained by inline-assembler codes.The default is:
44*17c3b001SJiri Olsa  *
45*17c3b001SJiri Olsa  *  #define USDT_ARG_CONSTRAINT nor
46*17c3b001SJiri Olsa  *
47*17c3b001SJiri Olsa  *  This is a good default if the operands tend to be integral and
48*17c3b001SJiri Olsa  *  moderate in number (smaller than number of registers). In other
49*17c3b001SJiri Olsa  *  cases, the compiler may report "'asm' requires impossible reload" or
50*17c3b001SJiri Olsa  *  similar. In this case, consider simplifying the macro call (fewer
51*17c3b001SJiri Olsa  *  and simpler operands), reduce optimization, or override the default
52*17c3b001SJiri Olsa  *  constraints string via:
53*17c3b001SJiri Olsa  *
54*17c3b001SJiri Olsa  *  #define USDT_ARG_CONSTRAINT g
55*17c3b001SJiri Olsa  *  #include <usdt.h>
56*17c3b001SJiri Olsa  *
57*17c3b001SJiri Olsa  * For some historical description of USDT v3 format (the one used by this
58*17c3b001SJiri Olsa  * library and generally recognized and assumed by BPF-based tracing tools)
59*17c3b001SJiri Olsa  * see [0]. The more formal specification can be found at [1]. Additional
60*17c3b001SJiri Olsa  * argument constraints information can be found at [2].
61*17c3b001SJiri Olsa  *
62*17c3b001SJiri Olsa  * Original SystemTap's sys/sdt.h implementation ([3]) was used as a base for
63*17c3b001SJiri Olsa  * this USDT library implementation. Current implementation differs *a lot* in
64*17c3b001SJiri Olsa  * terms of exposed user API and general usability, which was the main goal
65*17c3b001SJiri Olsa  * and focus of the reimplementation work. Nevertheless, underlying recorded
66*17c3b001SJiri Olsa  * USDT definitions are fully binary compatible and any USDT-based tooling
67*17c3b001SJiri Olsa  * should work equally well with USDTs defined by either SystemTap's or this
68*17c3b001SJiri Olsa  * library's USDT implementation.
69*17c3b001SJiri Olsa  *
70*17c3b001SJiri Olsa  *   [0] https://ecos.sourceware.org/ml/systemtap/2010-q3/msg00145.html
71*17c3b001SJiri Olsa  *   [1] https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
72*17c3b001SJiri Olsa  *   [2] https://gcc.gnu.org/onlinedocs/gcc/Constraints.html
73*17c3b001SJiri Olsa  *   [3] https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h
74*17c3b001SJiri Olsa  */
75*17c3b001SJiri Olsa #ifndef __USDT_H
76*17c3b001SJiri Olsa #define __USDT_H
77*17c3b001SJiri Olsa 
78*17c3b001SJiri Olsa /*
79*17c3b001SJiri Olsa  * Changelog:
80*17c3b001SJiri Olsa  *
81*17c3b001SJiri Olsa  * 0.1.0
82*17c3b001SJiri Olsa  * -----
83*17c3b001SJiri Olsa  * - Initial release
84*17c3b001SJiri Olsa  */
85*17c3b001SJiri Olsa #define USDT_MAJOR_VERSION 0
86*17c3b001SJiri Olsa #define USDT_MINOR_VERSION 1
87*17c3b001SJiri Olsa #define USDT_PATCH_VERSION 0
88*17c3b001SJiri Olsa 
89*17c3b001SJiri Olsa /* C++20 and C23 added __VA_OPT__ as a standard replacement for non-standard `##__VA_ARGS__` extension */
90*17c3b001SJiri Olsa #if (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L) || (defined(__cplusplus) && __cplusplus > 201703L)
91*17c3b001SJiri Olsa #define __usdt_va_opt 1
92*17c3b001SJiri Olsa #define __usdt_va_args(...) __VA_OPT__(,) __VA_ARGS__
93*17c3b001SJiri Olsa #else
94*17c3b001SJiri Olsa #define __usdt_va_args(...) , ##__VA_ARGS__
95*17c3b001SJiri Olsa #endif
96*17c3b001SJiri Olsa 
97*17c3b001SJiri Olsa /*
98*17c3b001SJiri Olsa  * Trigger USDT with `group`:`name` identifier and pass through `args` as its
99*17c3b001SJiri Olsa  * arguments. Zero arguments are acceptable as well. No USDT semaphore is
100*17c3b001SJiri Olsa  * associated with this USDT.
101*17c3b001SJiri Olsa  *
102*17c3b001SJiri Olsa  * Such "semaphoreless" USDTs are commonly used when there is no extra data
103*17c3b001SJiri Olsa  * collection or processing needed to collect and prepare USDT arguments and
104*17c3b001SJiri Olsa  * they are just available in the surrounding code. USDT() macro will just
105*17c3b001SJiri Olsa  * record their locations in CPU registers or in memory for tracing tooling to
106*17c3b001SJiri Olsa  * be able to access them, if necessary.
107*17c3b001SJiri Olsa  */
108*17c3b001SJiri Olsa #ifdef __usdt_va_opt
109*17c3b001SJiri Olsa #define USDT(group, name, ...)							\
110*17c3b001SJiri Olsa 	__usdt_probe(group, name, __usdt_sema_none, 0 __VA_OPT__(,) __VA_ARGS__)
111*17c3b001SJiri Olsa #else
112*17c3b001SJiri Olsa #define USDT(group, name, ...)							\
113*17c3b001SJiri Olsa 	__usdt_probe(group, name, __usdt_sema_none, 0, ##__VA_ARGS__)
114*17c3b001SJiri Olsa #endif
115*17c3b001SJiri Olsa 
116*17c3b001SJiri Olsa /*
117*17c3b001SJiri Olsa  * Trigger USDT with `group`:`name` identifier and pass through `args` as its
118*17c3b001SJiri Olsa  * arguments. Zero arguments are acceptable as well. USDT also get an
119*17c3b001SJiri Olsa  * implicitly-defined associated USDT semaphore, which will be "activated" by
120*17c3b001SJiri Olsa  * tracing tooling and can be used to check whether USDT is being actively
121*17c3b001SJiri Olsa  * observed.
122*17c3b001SJiri Olsa  *
123*17c3b001SJiri Olsa  * USDTs with semaphore are commonly used when there is a need to perform
124*17c3b001SJiri Olsa  * additional data collection and processing to prepare USDT arguments, which
125*17c3b001SJiri Olsa  * otherwise might not be necessary for the rest of application logic. In such
126*17c3b001SJiri Olsa  * case, USDT semaphore can be used to avoid unnecessary extra work. If USDT
127*17c3b001SJiri Olsa  * is not traced (which is presumed to be a common situation), the associated
128*17c3b001SJiri Olsa  * USDT semaphore is "inactive", and so there is no need to waste resources to
129*17c3b001SJiri Olsa  * prepare USDT arguments. Use USDT_IS_ACTIVE(group, name) to check whether
130*17c3b001SJiri Olsa  * USDT is "active".
131*17c3b001SJiri Olsa  *
132*17c3b001SJiri Olsa  * N.B. There is an inherent (albeit short) gap between checking whether USDT
133*17c3b001SJiri Olsa  * is active and triggering corresponding USDT, in which external tracer can
134*17c3b001SJiri Olsa  * be attached to an USDT and activate USDT semaphore after the activity check.
135*17c3b001SJiri Olsa  * If such a race occurs, tracers might miss one USDT execution. Tracers are
136*17c3b001SJiri Olsa  * expected to accommodate such possibility and this is expected to not be
137*17c3b001SJiri Olsa  * a problem for applications and tracers.
138*17c3b001SJiri Olsa  *
139*17c3b001SJiri Olsa  * N.B. Implicit USDT semaphore defined by USDT_WITH_SEMA() is contained
140*17c3b001SJiri Olsa  * within a single executable or shared library and is not shared outside
141*17c3b001SJiri Olsa  * them. I.e., if you use USDT_WITH_SEMA() with the same USDT group and name
142*17c3b001SJiri Olsa  * identifier across executable and shared library, it will work and won't
143*17c3b001SJiri Olsa  * conflict, per se, but will define independent USDT semaphores, one for each
144*17c3b001SJiri Olsa  * shared library/executable in which USDT_WITH_SEMA(group, name) is used.
145*17c3b001SJiri Olsa  * That is, if you attach to this USDT in one shared library (or executable),
146*17c3b001SJiri Olsa  * then only USDT semaphore within that shared library (or executable) will be
147*17c3b001SJiri Olsa  * updated by the kernel, while other libraries (or executable) will not see
148*17c3b001SJiri Olsa  * activated USDT semaphore. In short, it's best to use unique USDT group:name
149*17c3b001SJiri Olsa  * identifiers across different shared libraries (and, equivalently, between
150*17c3b001SJiri Olsa  * executable and shared library). This is advanced consideration and is
151*17c3b001SJiri Olsa  * rarely (if ever) seen in practice, but just to avoid surprises this is
152*17c3b001SJiri Olsa  * called out here. (Static libraries become a part of final executable, once
153*17c3b001SJiri Olsa  * linked by linker, so the above considerations don't apply to them.)
154*17c3b001SJiri Olsa  */
155*17c3b001SJiri Olsa #ifdef __usdt_va_opt
156*17c3b001SJiri Olsa #define USDT_WITH_SEMA(group, name, ...)					\
157*17c3b001SJiri Olsa 	__usdt_probe(group, name,						\
158*17c3b001SJiri Olsa 		     __usdt_sema_implicit, __usdt_sema_name(group, name)	\
159*17c3b001SJiri Olsa 		     __VA_OPT__(,) __VA_ARGS__)
160*17c3b001SJiri Olsa #else
161*17c3b001SJiri Olsa #define USDT_WITH_SEMA(group, name, ...)					\
162*17c3b001SJiri Olsa 	__usdt_probe(group, name,						\
163*17c3b001SJiri Olsa 		     __usdt_sema_implicit, __usdt_sema_name(group, name),	\
164*17c3b001SJiri Olsa 		     ##__VA_ARGS__)
165*17c3b001SJiri Olsa #endif
166*17c3b001SJiri Olsa 
167*17c3b001SJiri Olsa struct usdt_sema { volatile unsigned short active; };
168*17c3b001SJiri Olsa 
169*17c3b001SJiri Olsa /*
170*17c3b001SJiri Olsa  * Check if USDT with `group`:`name` identifier is "active" (i.e., whether it
171*17c3b001SJiri Olsa  * is attached to by external tracing tooling and is actively observed).
172*17c3b001SJiri Olsa  *
173*17c3b001SJiri Olsa  * This macro can be used to decide whether any additional and potentially
174*17c3b001SJiri Olsa  * expensive data collection or processing should be done to pass extra
175*17c3b001SJiri Olsa  * information into the given USDT. It is assumed that USDT is triggered with
176*17c3b001SJiri Olsa  * USDT_WITH_SEMA() macro which will implicitly define associated USDT
177*17c3b001SJiri Olsa  * semaphore. (If one needs more control over USDT semaphore, see
178*17c3b001SJiri Olsa  * USDT_DEFINE_SEMA() and USDT_WITH_EXPLICIT_SEMA() macros below.)
179*17c3b001SJiri Olsa  *
180*17c3b001SJiri Olsa  * N.B. Such checks are necessarily racy and speculative. Between checking
181*17c3b001SJiri Olsa  * whether USDT is active and triggering the USDT itself, tracer can be
182*17c3b001SJiri Olsa  * detached with no notification. This race should be extremely rare and worst
183*17c3b001SJiri Olsa  * case should result in one-time wasted extra data collection and processing.
184*17c3b001SJiri Olsa  */
185*17c3b001SJiri Olsa #define USDT_IS_ACTIVE(group, name) ({						\
186*17c3b001SJiri Olsa 	extern struct usdt_sema __usdt_sema_name(group, name)			\
187*17c3b001SJiri Olsa 		__usdt_asm_name(__usdt_sema_name(group, name));			\
188*17c3b001SJiri Olsa 	__usdt_sema_implicit(__usdt_sema_name(group, name));			\
189*17c3b001SJiri Olsa 	__usdt_sema_name(group, name).active > 0;				\
190*17c3b001SJiri Olsa })
191*17c3b001SJiri Olsa 
192*17c3b001SJiri Olsa /*
193*17c3b001SJiri Olsa  * APIs for working with user-defined explicit USDT semaphores.
194*17c3b001SJiri Olsa  *
195*17c3b001SJiri Olsa  * This is a less commonly used advanced API for use cases in which user needs
196*17c3b001SJiri Olsa  * an explicit control over (potentially shared across multiple USDTs) USDT
197*17c3b001SJiri Olsa  * semaphore instance. This can be used when there is a group of logically
198*17c3b001SJiri Olsa  * related USDTs that all need extra data collection and processing whenever
199*17c3b001SJiri Olsa  * any of a family of related USDTs are "activated" (i.e., traced). In such
200*17c3b001SJiri Olsa  * a case, all such related USDTs will be associated with the same shared USDT
201*17c3b001SJiri Olsa  * semaphore defined with USDT_DEFINE_SEMA() and the USDTs themselves will be
202*17c3b001SJiri Olsa  * triggered with USDT_WITH_EXPLICIT_SEMA() macros, taking an explicit extra
203*17c3b001SJiri Olsa  * USDT semaphore identifier as an extra parameter.
204*17c3b001SJiri Olsa  */
205*17c3b001SJiri Olsa 
206*17c3b001SJiri Olsa /**
207*17c3b001SJiri Olsa  * Underlying C global variable name for user-defined USDT semaphore with
208*17c3b001SJiri Olsa  * `sema` identifier. Could be useful for debugging, but normally shouldn't be
209*17c3b001SJiri Olsa  * used explicitly.
210*17c3b001SJiri Olsa  */
211*17c3b001SJiri Olsa #define USDT_SEMA(sema) __usdt_sema_##sema
212*17c3b001SJiri Olsa 
213*17c3b001SJiri Olsa /*
214*17c3b001SJiri Olsa  * Define storage for user-defined USDT semaphore `sema`.
215*17c3b001SJiri Olsa  *
216*17c3b001SJiri Olsa  * Should be used only once in non-header source file to let compiler allocate
217*17c3b001SJiri Olsa  * space for the semaphore variable. Just like with any other global variable.
218*17c3b001SJiri Olsa  *
219*17c3b001SJiri Olsa  * This macro can be used anywhere where global variable declaration is
220*17c3b001SJiri Olsa  * allowed. Just like with global variable definitions, there should be only
221*17c3b001SJiri Olsa  * one definition of user-defined USDT semaphore with given `sema` identifier,
222*17c3b001SJiri Olsa  * otherwise compiler or linker will complain about duplicate variable
223*17c3b001SJiri Olsa  * definition.
224*17c3b001SJiri Olsa  *
225*17c3b001SJiri Olsa  * For C++, it is allowed to use USDT_DEFINE_SEMA() both in global namespace
226*17c3b001SJiri Olsa  * and inside namespaces (including nested namespaces). Just make sure that
227*17c3b001SJiri Olsa  * USDT_DECLARE_SEMA() is placed within the namespace where this semaphore is
228*17c3b001SJiri Olsa  * referenced, or any of its parent namespaces, so the C++ language-level
229*17c3b001SJiri Olsa  * identifier is visible to the code that needs to reference the semaphore.
230*17c3b001SJiri Olsa  * At the lowest layer, USDT semaphores have global naming and visibility
231*17c3b001SJiri Olsa  * (they have a corresponding `__usdt_sema_<name>` symbol, which can be linked
232*17c3b001SJiri Olsa  * against from C or C++ code, if necessary). To keep it simple, putting
233*17c3b001SJiri Olsa  * USDT_DECLARE_SEMA() declarations into global namespaces is the simplest
234*17c3b001SJiri Olsa  * no-brainer solution. All these aspects are irrelevant for plain C, because
235*17c3b001SJiri Olsa  * C doesn't have namespaces and everything is always in the global namespace.
236*17c3b001SJiri Olsa  *
237*17c3b001SJiri Olsa  * N.B. Due to USDT metadata being recorded in non-allocatable ELF note
238*17c3b001SJiri Olsa  * section, it has limitations when it comes to relocations, which, in
239*17c3b001SJiri Olsa  * practice, means that it's not possible to correctly share USDT semaphores
240*17c3b001SJiri Olsa  * between main executable and shared libraries, or even between multiple
241*17c3b001SJiri Olsa  * shared libraries. USDT semaphore has to be contained to individual shared
242*17c3b001SJiri Olsa  * library or executable to avoid unpleasant surprises with half-working USDT
243*17c3b001SJiri Olsa  * semaphores. We enforce this by marking semaphore ELF symbols as having
244*17c3b001SJiri Olsa  * a hidden visibility. This is quite an advanced use case and consideration
245*17c3b001SJiri Olsa  * and for most users this should have no consequences whatsoever.
246*17c3b001SJiri Olsa  */
247*17c3b001SJiri Olsa #define USDT_DEFINE_SEMA(sema)							\
248*17c3b001SJiri Olsa 	struct usdt_sema __usdt_sema_sec USDT_SEMA(sema)			\
249*17c3b001SJiri Olsa 		__usdt_asm_name(USDT_SEMA(sema))				\
250*17c3b001SJiri Olsa 		__attribute__((visibility("hidden"))) = { 0 }
251*17c3b001SJiri Olsa 
252*17c3b001SJiri Olsa /*
253*17c3b001SJiri Olsa  * Declare extern reference to user-defined USDT semaphore `sema`.
254*17c3b001SJiri Olsa  *
255*17c3b001SJiri Olsa  * Refers to a variable defined in another compilation unit by
256*17c3b001SJiri Olsa  * USDT_DEFINE_SEMA() and allows to use the same USDT semaphore across
257*17c3b001SJiri Olsa  * multiple compilation units (i.e., .c and .cpp files).
258*17c3b001SJiri Olsa  *
259*17c3b001SJiri Olsa  * See USDT_DEFINE_SEMA() notes above for C++ language usage peculiarities.
260*17c3b001SJiri Olsa  */
261*17c3b001SJiri Olsa #define USDT_DECLARE_SEMA(sema)							\
262*17c3b001SJiri Olsa 	extern struct usdt_sema USDT_SEMA(sema) __usdt_asm_name(USDT_SEMA(sema))
263*17c3b001SJiri Olsa 
264*17c3b001SJiri Olsa /*
265*17c3b001SJiri Olsa  * Check if user-defined USDT semaphore `sema` is "active" (i.e., whether it
266*17c3b001SJiri Olsa  * is attached to by external tracing tooling and is actively observed).
267*17c3b001SJiri Olsa  *
268*17c3b001SJiri Olsa  * This macro can be used to decide whether any additional and potentially
269*17c3b001SJiri Olsa  * expensive data collection or processing should be done to pass extra
270*17c3b001SJiri Olsa  * information into USDT(s) associated with USDT semaphore `sema`.
271*17c3b001SJiri Olsa  *
272*17c3b001SJiri Olsa  * N.B. Such checks are necessarily racy. Between checking the state of USDT
273*17c3b001SJiri Olsa  * semaphore and triggering associated USDT(s), the active tracer might attach
274*17c3b001SJiri Olsa  * or detach. This race should be extremely rare and worst case should result
275*17c3b001SJiri Olsa  * in one-time missed USDT event or wasted extra data collection and
276*17c3b001SJiri Olsa  * processing. USDT-using tracers should be written with this in mind and is
277*17c3b001SJiri Olsa  * not a concern of the application defining USDTs with associated semaphore.
278*17c3b001SJiri Olsa  */
279*17c3b001SJiri Olsa #define USDT_SEMA_IS_ACTIVE(sema) (USDT_SEMA(sema).active > 0)
280*17c3b001SJiri Olsa 
281*17c3b001SJiri Olsa /*
282*17c3b001SJiri Olsa  * Invoke USDT specified by `group` and `name` identifiers and associate
283*17c3b001SJiri Olsa  * explicitly user-defined semaphore `sema` with it. Pass through `args` as
284*17c3b001SJiri Olsa  * USDT arguments. `args` are optional and zero arguments are acceptable.
285*17c3b001SJiri Olsa  *
286*17c3b001SJiri Olsa  * Semaphore is defined with the help of USDT_DEFINE_SEMA() macro and can be
287*17c3b001SJiri Olsa  * checked whether active with USDT_SEMA_IS_ACTIVE().
288*17c3b001SJiri Olsa  */
289*17c3b001SJiri Olsa #ifdef __usdt_va_opt
290*17c3b001SJiri Olsa #define USDT_WITH_EXPLICIT_SEMA(sema, group, name, ...)				\
291*17c3b001SJiri Olsa 	__usdt_probe(group, name, __usdt_sema_explicit, USDT_SEMA(sema), ##__VA_ARGS__)
292*17c3b001SJiri Olsa #else
293*17c3b001SJiri Olsa #define USDT_WITH_EXPLICIT_SEMA(sema, group, name, ...)				\
294*17c3b001SJiri Olsa 	__usdt_probe(group, name, __usdt_sema_explicit, USDT_SEMA(sema) __VA_OPT__(,) __VA_ARGS__)
295*17c3b001SJiri Olsa #endif
296*17c3b001SJiri Olsa 
297*17c3b001SJiri Olsa /*
298*17c3b001SJiri Olsa  * Adjustable implementation aspects
299*17c3b001SJiri Olsa  */
300*17c3b001SJiri Olsa #ifndef USDT_ARG_CONSTRAINT
301*17c3b001SJiri Olsa #if defined __powerpc__
302*17c3b001SJiri Olsa #define USDT_ARG_CONSTRAINT		nZr
303*17c3b001SJiri Olsa #elif defined __arm__
304*17c3b001SJiri Olsa #define USDT_ARG_CONSTRAINT		g
305*17c3b001SJiri Olsa #elif defined __loongarch__
306*17c3b001SJiri Olsa #define USDT_ARG_CONSTRAINT		nmr
307*17c3b001SJiri Olsa #else
308*17c3b001SJiri Olsa #define USDT_ARG_CONSTRAINT		nor
309*17c3b001SJiri Olsa #endif
310*17c3b001SJiri Olsa #endif /* USDT_ARG_CONSTRAINT */
311*17c3b001SJiri Olsa 
312*17c3b001SJiri Olsa #ifndef USDT_NOP
313*17c3b001SJiri Olsa #if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
314*17c3b001SJiri Olsa #define USDT_NOP			nop 0
315*17c3b001SJiri Olsa #else
316*17c3b001SJiri Olsa #define USDT_NOP			nop
317*17c3b001SJiri Olsa #endif
318*17c3b001SJiri Olsa #endif /* USDT_NOP */
319*17c3b001SJiri Olsa 
320*17c3b001SJiri Olsa /*
321*17c3b001SJiri Olsa  * Implementation details
322*17c3b001SJiri Olsa  */
323*17c3b001SJiri Olsa /* USDT name for implicitly-defined USDT semaphore, derived from group:name */
324*17c3b001SJiri Olsa #define __usdt_sema_name(group, name)	__usdt_sema_##group##__##name
325*17c3b001SJiri Olsa /* ELF section into which USDT semaphores are put */
326*17c3b001SJiri Olsa #define __usdt_sema_sec			__attribute__((section(".probes")))
327*17c3b001SJiri Olsa 
328*17c3b001SJiri Olsa #define __usdt_concat(a, b)		a ## b
329*17c3b001SJiri Olsa #define __usdt_apply(fn, n)		__usdt_concat(fn, n)
330*17c3b001SJiri Olsa 
331*17c3b001SJiri Olsa #ifndef __usdt_nth
332*17c3b001SJiri Olsa #define __usdt_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
333*17c3b001SJiri Olsa #endif
334*17c3b001SJiri Olsa 
335*17c3b001SJiri Olsa #ifndef __usdt_narg
336*17c3b001SJiri Olsa #ifdef __usdt_va_opt
337*17c3b001SJiri Olsa #define __usdt_narg(...) __usdt_nth(_ __VA_OPT__(,) __VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
338*17c3b001SJiri Olsa #else
339*17c3b001SJiri Olsa #define __usdt_narg(...) __usdt_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
340*17c3b001SJiri Olsa #endif
341*17c3b001SJiri Olsa #endif /* __usdt_narg */
342*17c3b001SJiri Olsa 
343*17c3b001SJiri Olsa #define __usdt_hash			#
344*17c3b001SJiri Olsa #define __usdt_str_(x)			#x
345*17c3b001SJiri Olsa #define __usdt_str(x)			__usdt_str_(x)
346*17c3b001SJiri Olsa 
347*17c3b001SJiri Olsa #ifndef __usdt_asm_name
348*17c3b001SJiri Olsa #define __usdt_asm_name(name)		__asm__(__usdt_str(name))
349*17c3b001SJiri Olsa #endif
350*17c3b001SJiri Olsa 
351*17c3b001SJiri Olsa #define __usdt_asm0()		"\n"
352*17c3b001SJiri Olsa #define __usdt_asm1(x)		__usdt_str(x) "\n"
353*17c3b001SJiri Olsa #define __usdt_asm2(x, ...)	__usdt_str(x) "," __usdt_asm1(__VA_ARGS__)
354*17c3b001SJiri Olsa #define __usdt_asm3(x, ...)	__usdt_str(x) "," __usdt_asm2(__VA_ARGS__)
355*17c3b001SJiri Olsa #define __usdt_asm4(x, ...)	__usdt_str(x) "," __usdt_asm3(__VA_ARGS__)
356*17c3b001SJiri Olsa #define __usdt_asm5(x, ...)	__usdt_str(x) "," __usdt_asm4(__VA_ARGS__)
357*17c3b001SJiri Olsa #define __usdt_asm6(x, ...)	__usdt_str(x) "," __usdt_asm5(__VA_ARGS__)
358*17c3b001SJiri Olsa #define __usdt_asm7(x, ...)	__usdt_str(x) "," __usdt_asm6(__VA_ARGS__)
359*17c3b001SJiri Olsa #define __usdt_asm8(x, ...)	__usdt_str(x) "," __usdt_asm7(__VA_ARGS__)
360*17c3b001SJiri Olsa #define __usdt_asm9(x, ...)	__usdt_str(x) "," __usdt_asm8(__VA_ARGS__)
361*17c3b001SJiri Olsa #define __usdt_asm10(x, ...)	__usdt_str(x) "," __usdt_asm9(__VA_ARGS__)
362*17c3b001SJiri Olsa #define __usdt_asm11(x, ...)	__usdt_str(x) "," __usdt_asm10(__VA_ARGS__)
363*17c3b001SJiri Olsa #define __usdt_asm12(x, ...)	__usdt_str(x) "," __usdt_asm11(__VA_ARGS__)
364*17c3b001SJiri Olsa #define __usdt_asm(...)		__usdt_apply(__usdt_asm, __usdt_narg(__VA_ARGS__))(__VA_ARGS__)
365*17c3b001SJiri Olsa 
366*17c3b001SJiri Olsa #ifdef __LP64__
367*17c3b001SJiri Olsa #define __usdt_asm_addr		.8byte
368*17c3b001SJiri Olsa #else
369*17c3b001SJiri Olsa #define __usdt_asm_addr		.4byte
370*17c3b001SJiri Olsa #endif
371*17c3b001SJiri Olsa 
372*17c3b001SJiri Olsa #define __usdt_asm_strz_(x)	__usdt_asm1(.asciz #x)
373*17c3b001SJiri Olsa #define __usdt_asm_strz(x)	__usdt_asm_strz_(x)
374*17c3b001SJiri Olsa #define __usdt_asm_str_(x)	__usdt_asm1(.ascii #x)
375*17c3b001SJiri Olsa #define __usdt_asm_str(x)	__usdt_asm_str_(x)
376*17c3b001SJiri Olsa 
377*17c3b001SJiri Olsa /* "semaphoreless" USDT case */
378*17c3b001SJiri Olsa #ifndef __usdt_sema_none
379*17c3b001SJiri Olsa #define __usdt_sema_none(sema)
380*17c3b001SJiri Olsa #endif
381*17c3b001SJiri Olsa 
382*17c3b001SJiri Olsa /* implicitly defined __usdt_sema__group__name semaphore (using weak symbols) */
383*17c3b001SJiri Olsa #ifndef __usdt_sema_implicit
384*17c3b001SJiri Olsa #define __usdt_sema_implicit(sema)								\
385*17c3b001SJiri Olsa 	__asm__ __volatile__ (									\
386*17c3b001SJiri Olsa 	__usdt_asm1(.ifndef sema)								\
387*17c3b001SJiri Olsa 	__usdt_asm3(		.pushsection .probes, "aw", "progbits")				\
388*17c3b001SJiri Olsa 	__usdt_asm1(		.weak sema)							\
389*17c3b001SJiri Olsa 	__usdt_asm1(		.hidden sema)							\
390*17c3b001SJiri Olsa 	__usdt_asm1(		.align 2)							\
391*17c3b001SJiri Olsa 	__usdt_asm1(sema:)									\
392*17c3b001SJiri Olsa 	__usdt_asm1(		.zero 2)							\
393*17c3b001SJiri Olsa 	__usdt_asm2(		.type sema, @object)						\
394*17c3b001SJiri Olsa 	__usdt_asm2(		.size sema, 2)							\
395*17c3b001SJiri Olsa 	__usdt_asm1(		.popsection)							\
396*17c3b001SJiri Olsa 	__usdt_asm1(.endif)									\
397*17c3b001SJiri Olsa 	);
398*17c3b001SJiri Olsa #endif
399*17c3b001SJiri Olsa 
400*17c3b001SJiri Olsa /* externally defined semaphore using USDT_DEFINE_SEMA() and passed explicitly by user */
401*17c3b001SJiri Olsa #ifndef __usdt_sema_explicit
402*17c3b001SJiri Olsa #define __usdt_sema_explicit(sema)								\
403*17c3b001SJiri Olsa 	__asm__ __volatile__ ("" :: "m" (sema));
404*17c3b001SJiri Olsa #endif
405*17c3b001SJiri Olsa 
406*17c3b001SJiri Olsa /* main USDT definition (nop and .note.stapsdt metadata) */
407*17c3b001SJiri Olsa #define __usdt_probe(group, name, sema_def, sema, ...) do {					\
408*17c3b001SJiri Olsa 	sema_def(sema)										\
409*17c3b001SJiri Olsa 	__asm__ __volatile__ (									\
410*17c3b001SJiri Olsa 	__usdt_asm( 990:	USDT_NOP)							\
411*17c3b001SJiri Olsa 	__usdt_asm3(		.pushsection .note.stapsdt, "", "note")				\
412*17c3b001SJiri Olsa 	__usdt_asm1(		.balign 4)							\
413*17c3b001SJiri Olsa 	__usdt_asm3(		.4byte 992f-991f,994f-993f,3)					\
414*17c3b001SJiri Olsa 	__usdt_asm1(991:	.asciz "stapsdt")						\
415*17c3b001SJiri Olsa 	__usdt_asm1(992:	.balign 4)							\
416*17c3b001SJiri Olsa 	__usdt_asm1(993:	__usdt_asm_addr 990b)						\
417*17c3b001SJiri Olsa 	__usdt_asm1(		__usdt_asm_addr _.stapsdt.base)					\
418*17c3b001SJiri Olsa 	__usdt_asm1(		__usdt_asm_addr sema)						\
419*17c3b001SJiri Olsa 	__usdt_asm_strz(group)									\
420*17c3b001SJiri Olsa 	__usdt_asm_strz(name)									\
421*17c3b001SJiri Olsa 	__usdt_asm_args(__VA_ARGS__)								\
422*17c3b001SJiri Olsa 	__usdt_asm1(		.ascii "\0")							\
423*17c3b001SJiri Olsa 	__usdt_asm1(994:	.balign 4)							\
424*17c3b001SJiri Olsa 	__usdt_asm1(		.popsection)							\
425*17c3b001SJiri Olsa 	__usdt_asm1(.ifndef _.stapsdt.base)							\
426*17c3b001SJiri Olsa 	__usdt_asm5(		.pushsection .stapsdt.base,"aG","progbits",.stapsdt.base,comdat)\
427*17c3b001SJiri Olsa 	__usdt_asm1(		.weak _.stapsdt.base)						\
428*17c3b001SJiri Olsa 	__usdt_asm1(		.hidden _.stapsdt.base)						\
429*17c3b001SJiri Olsa 	__usdt_asm1(_.stapsdt.base:)								\
430*17c3b001SJiri Olsa 	__usdt_asm1(		.space 1)							\
431*17c3b001SJiri Olsa 	__usdt_asm2(		.size _.stapsdt.base, 1)					\
432*17c3b001SJiri Olsa 	__usdt_asm1(		.popsection)							\
433*17c3b001SJiri Olsa 	__usdt_asm1(.endif)									\
434*17c3b001SJiri Olsa 	:: __usdt_asm_ops(__VA_ARGS__)								\
435*17c3b001SJiri Olsa 	);											\
436*17c3b001SJiri Olsa } while (0)
437*17c3b001SJiri Olsa 
438*17c3b001SJiri Olsa /*
439*17c3b001SJiri Olsa  * NB: gdb PR24541 highlighted an unspecified corner of the sdt.h
440*17c3b001SJiri Olsa  * operand note format.
441*17c3b001SJiri Olsa  *
442*17c3b001SJiri Olsa  * The named register may be a longer or shorter (!) alias for the
443*17c3b001SJiri Olsa  * storage where the value in question is found. For example, on
444*17c3b001SJiri Olsa  * i386, 64-bit value may be put in register pairs, and a register
445*17c3b001SJiri Olsa  * name stored would identify just one of them. Previously, gcc was
446*17c3b001SJiri Olsa  * asked to emit the %w[id] (16-bit alias of some registers holding
447*17c3b001SJiri Olsa  * operands), even when a wider 32-bit value was used.
448*17c3b001SJiri Olsa  *
449*17c3b001SJiri Olsa  * Bottom line: the byte-width given before the @ sign governs. If
450*17c3b001SJiri Olsa  * there is a mismatch between that width and that of the named
451*17c3b001SJiri Olsa  * register, then a sys/sdt.h note consumer may need to employ
452*17c3b001SJiri Olsa  * architecture-specific heuristics to figure out where the compiler
453*17c3b001SJiri Olsa  * has actually put the complete value.
454*17c3b001SJiri Olsa  */
455*17c3b001SJiri Olsa #if defined(__powerpc__) || defined(__powerpc64__)
456*17c3b001SJiri Olsa #define __usdt_argref(id)	%I[id]%[id]
457*17c3b001SJiri Olsa #elif defined(__i386__)
458*17c3b001SJiri Olsa #define __usdt_argref(id)	%k[id]		/* gcc.gnu.org/PR80115 sourceware.org/PR24541 */
459*17c3b001SJiri Olsa #else
460*17c3b001SJiri Olsa #define __usdt_argref(id)	%[id]
461*17c3b001SJiri Olsa #endif
462*17c3b001SJiri Olsa 
463*17c3b001SJiri Olsa #define __usdt_asm_arg(n)	__usdt_asm_str(%c[__usdt_asz##n])				\
464*17c3b001SJiri Olsa 				__usdt_asm1(.ascii "@")						\
465*17c3b001SJiri Olsa 				__usdt_asm_str(__usdt_argref(__usdt_aval##n))
466*17c3b001SJiri Olsa 
467*17c3b001SJiri Olsa #define __usdt_asm_args0	/* no arguments */
468*17c3b001SJiri Olsa #define __usdt_asm_args1	__usdt_asm_arg(1)
469*17c3b001SJiri Olsa #define __usdt_asm_args2	__usdt_asm_args1 __usdt_asm1(.ascii " ") __usdt_asm_arg(2)
470*17c3b001SJiri Olsa #define __usdt_asm_args3	__usdt_asm_args2 __usdt_asm1(.ascii " ") __usdt_asm_arg(3)
471*17c3b001SJiri Olsa #define __usdt_asm_args4	__usdt_asm_args3 __usdt_asm1(.ascii " ") __usdt_asm_arg(4)
472*17c3b001SJiri Olsa #define __usdt_asm_args5	__usdt_asm_args4 __usdt_asm1(.ascii " ") __usdt_asm_arg(5)
473*17c3b001SJiri Olsa #define __usdt_asm_args6	__usdt_asm_args5 __usdt_asm1(.ascii " ") __usdt_asm_arg(6)
474*17c3b001SJiri Olsa #define __usdt_asm_args7	__usdt_asm_args6 __usdt_asm1(.ascii " ") __usdt_asm_arg(7)
475*17c3b001SJiri Olsa #define __usdt_asm_args8	__usdt_asm_args7 __usdt_asm1(.ascii " ") __usdt_asm_arg(8)
476*17c3b001SJiri Olsa #define __usdt_asm_args9	__usdt_asm_args8 __usdt_asm1(.ascii " ") __usdt_asm_arg(9)
477*17c3b001SJiri Olsa #define __usdt_asm_args10	__usdt_asm_args9 __usdt_asm1(.ascii " ") __usdt_asm_arg(10)
478*17c3b001SJiri Olsa #define __usdt_asm_args11	__usdt_asm_args10 __usdt_asm1(.ascii " ") __usdt_asm_arg(11)
479*17c3b001SJiri Olsa #define __usdt_asm_args12	__usdt_asm_args11 __usdt_asm1(.ascii " ") __usdt_asm_arg(12)
480*17c3b001SJiri Olsa #define __usdt_asm_args(...)	__usdt_apply(__usdt_asm_args, __usdt_narg(__VA_ARGS__))
481*17c3b001SJiri Olsa 
482*17c3b001SJiri Olsa #define __usdt_is_arr(x)	(__builtin_classify_type(x) == 14 || __builtin_classify_type(x) == 5)
483*17c3b001SJiri Olsa #define __usdt_arg_size(x)	(__usdt_is_arr(x) ? sizeof(void *) : sizeof(x))
484*17c3b001SJiri Olsa 
485*17c3b001SJiri Olsa /*
486*17c3b001SJiri Olsa  * We can't use __builtin_choose_expr() in C++, so fall back to table-based
487*17c3b001SJiri Olsa  * signedness determination for known types, utilizing templates magic.
488*17c3b001SJiri Olsa  */
489*17c3b001SJiri Olsa #ifdef __cplusplus
490*17c3b001SJiri Olsa 
491*17c3b001SJiri Olsa #define __usdt_is_signed(x)	(!__usdt_is_arr(x) && __usdt_t<__typeof(x)>::is_signed)
492*17c3b001SJiri Olsa 
493*17c3b001SJiri Olsa #include <cstddef>
494*17c3b001SJiri Olsa 
495*17c3b001SJiri Olsa template<typename T> struct __usdt_t { static const bool is_signed = false; };
496*17c3b001SJiri Olsa template<typename A> struct __usdt_t<A[]> : public __usdt_t<A *> {};
497*17c3b001SJiri Olsa template<typename A, size_t N> struct __usdt_t<A[N]> : public __usdt_t<A *> {};
498*17c3b001SJiri Olsa 
499*17c3b001SJiri Olsa #define __usdt_def_signed(T)									\
500*17c3b001SJiri Olsa template<> struct __usdt_t<T>		     { static const bool is_signed = true; };		\
501*17c3b001SJiri Olsa template<> struct __usdt_t<const T>	     { static const bool is_signed = true; };		\
502*17c3b001SJiri Olsa template<> struct __usdt_t<volatile T>	     { static const bool is_signed = true; };		\
503*17c3b001SJiri Olsa template<> struct __usdt_t<const volatile T> { static const bool is_signed = true; }
504*17c3b001SJiri Olsa #define __usdt_maybe_signed(T)									\
505*17c3b001SJiri Olsa template<> struct __usdt_t<T>		     { static const bool is_signed = (T)-1 < (T)1; };	\
506*17c3b001SJiri Olsa template<> struct __usdt_t<const T>	     { static const bool is_signed = (T)-1 < (T)1; };	\
507*17c3b001SJiri Olsa template<> struct __usdt_t<volatile T>	     { static const bool is_signed = (T)-1 < (T)1; };	\
508*17c3b001SJiri Olsa template<> struct __usdt_t<const volatile T> { static const bool is_signed = (T)-1 < (T)1; }
509*17c3b001SJiri Olsa 
510*17c3b001SJiri Olsa __usdt_def_signed(signed char);
511*17c3b001SJiri Olsa __usdt_def_signed(short);
512*17c3b001SJiri Olsa __usdt_def_signed(int);
513*17c3b001SJiri Olsa __usdt_def_signed(long);
514*17c3b001SJiri Olsa __usdt_def_signed(long long);
515*17c3b001SJiri Olsa __usdt_maybe_signed(char);
516*17c3b001SJiri Olsa __usdt_maybe_signed(wchar_t);
517*17c3b001SJiri Olsa 
518*17c3b001SJiri Olsa #else /* !__cplusplus */
519*17c3b001SJiri Olsa 
520*17c3b001SJiri Olsa #define __usdt_is_inttype(x)	(__builtin_classify_type(x) >= 1 && __builtin_classify_type(x) <= 4)
521*17c3b001SJiri Olsa #define __usdt_inttype(x)	__typeof(__builtin_choose_expr(__usdt_is_inttype(x), (x), 0U))
522*17c3b001SJiri Olsa #define __usdt_is_signed(x)	((__usdt_inttype(x))-1 < (__usdt_inttype(x))1)
523*17c3b001SJiri Olsa 
524*17c3b001SJiri Olsa #endif /* __cplusplus */
525*17c3b001SJiri Olsa 
526*17c3b001SJiri Olsa #define __usdt_asm_op(n, x)									\
527*17c3b001SJiri Olsa 	[__usdt_asz##n] "n" ((__usdt_is_signed(x) ? (int)-1 : 1) * (int)__usdt_arg_size(x)),	\
528*17c3b001SJiri Olsa 	[__usdt_aval##n] __usdt_str(USDT_ARG_CONSTRAINT)(x)
529*17c3b001SJiri Olsa 
530*17c3b001SJiri Olsa #define __usdt_asm_ops0()				[__usdt_dummy] "g" (0)
531*17c3b001SJiri Olsa #define __usdt_asm_ops1(x)				__usdt_asm_op(1, x)
532*17c3b001SJiri Olsa #define __usdt_asm_ops2(a,x)				__usdt_asm_ops1(a), __usdt_asm_op(2, x)
533*17c3b001SJiri Olsa #define __usdt_asm_ops3(a,b,x)				__usdt_asm_ops2(a,b), __usdt_asm_op(3, x)
534*17c3b001SJiri Olsa #define __usdt_asm_ops4(a,b,c,x)			__usdt_asm_ops3(a,b,c), __usdt_asm_op(4, x)
535*17c3b001SJiri Olsa #define __usdt_asm_ops5(a,b,c,d,x)			__usdt_asm_ops4(a,b,c,d), __usdt_asm_op(5, x)
536*17c3b001SJiri Olsa #define __usdt_asm_ops6(a,b,c,d,e,x)			__usdt_asm_ops5(a,b,c,d,e), __usdt_asm_op(6, x)
537*17c3b001SJiri Olsa #define __usdt_asm_ops7(a,b,c,d,e,f,x)			__usdt_asm_ops6(a,b,c,d,e,f), __usdt_asm_op(7, x)
538*17c3b001SJiri Olsa #define __usdt_asm_ops8(a,b,c,d,e,f,g,x)		__usdt_asm_ops7(a,b,c,d,e,f,g), __usdt_asm_op(8, x)
539*17c3b001SJiri Olsa #define __usdt_asm_ops9(a,b,c,d,e,f,g,h,x)		__usdt_asm_ops8(a,b,c,d,e,f,g,h), __usdt_asm_op(9, x)
540*17c3b001SJiri Olsa #define __usdt_asm_ops10(a,b,c,d,e,f,g,h,i,x)		__usdt_asm_ops9(a,b,c,d,e,f,g,h,i), __usdt_asm_op(10, x)
541*17c3b001SJiri Olsa #define __usdt_asm_ops11(a,b,c,d,e,f,g,h,i,j,x)		__usdt_asm_ops10(a,b,c,d,e,f,g,h,i,j), __usdt_asm_op(11, x)
542*17c3b001SJiri Olsa #define __usdt_asm_ops12(a,b,c,d,e,f,g,h,i,j,k,x)	__usdt_asm_ops11(a,b,c,d,e,f,g,h,i,j,k), __usdt_asm_op(12, x)
543*17c3b001SJiri Olsa #define __usdt_asm_ops(...)				__usdt_apply(__usdt_asm_ops, __usdt_narg(__VA_ARGS__))(__VA_ARGS__)
544*17c3b001SJiri Olsa 
545*17c3b001SJiri Olsa #endif /* __USDT_H */
546