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