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