1 module usdt; 2 3 version(UsdtProbesDisabled) 4 enum UsdtProbesDisabled = true; 5 else 6 enum UsdtProbesDisabled = false; 7 8 @safe @nogc pure nothrow 9 template USDT_PROBE(string provider, string name, Args...) if (UsdtProbesDisabled) 10 { 11 enum USDT_PROBE = "{}"; 12 } 13 14 @safe @nogc pure nothrow 15 template USDT_PROBE(string provider, string name, Args...) if (!UsdtProbesDisabled) 16 { 17 static if (Args.length > 12) 18 { 19 import std.conv : text; 20 pragma(msg, "Warning! SystemTap supports up to 12 arguments for probe. "); 21 pragma(msg, "You use " ~ Args.length.text ~ " arguments"); 22 static assert(0); 23 } 24 25 private enum USDT_PROBE_GDC = ` 26 asm @trusted { 27 "990: nop 28 .pushsection .note.stapsdt,\"?\",\"note\" 29 .balign 4 30 .4byte 992f-991f, 994f-993f, 3 31 991: .asciz \"stapsdt\" 32 992: .balign 4 33 993: .8byte 990b 34 .8byte _.stapsdt.base 35 .8byte 0 36 .asciz \"%1$s\" 37 .asciz \"%2$s\" 38 .asciz \"%3$s\" 39 994: .balign 4 40 .popsection 41 42 .ifndef _.stapsdt.base 43 .pushsection .stapsdt.base,\"aG\",\"progbits\", .stapsdt.base, comdat 44 .weak _.stapsdt.base 45 .hidden _.stapsdt.base 46 _.stapsdt.base: .space 1 47 .size _.stapsdt.base,1 48 .popsection 49 .endif" 50 :: %4$s; 51 }`; 52 53 private enum USDT_PROBE_LDC = " 54 import ldc.llvmasm; 55 56 __asm_trusted ( 57 `990: nop 58 .pushsection .note.stapsdt,\"?\",\"note\" 59 .balign 4 60 .4byte 992f-991f, 994f-993f, 3 61 991: .asciz \"stapsdt\" 62 992: .balign 4 63 993: .8byte 990b 64 .8byte _.stapsdt.base 65 .8byte 0 66 .asciz \"%1$s\" 67 .asciz \"%2$s\" 68 .asciz \"%3$s\" 69 994: .balign 4 70 .popsection 71 72 .ifndef _.stapsdt.base 73 .pushsection .stapsdt.base,\"aG\",\"progbits\", .stapsdt.base, comdat 74 .weak _.stapsdt.base 75 .hidden _.stapsdt.base 76 _.stapsdt.base: .space 1 77 .size _.stapsdt.base,1 78 .popsection 79 .endif`, \"%4$s\", %5$s 80 );"; 81 82 import std.format : format; 83 version(GNU) 84 enum USDT_PROBE = USDT_PROBE_GDC.format( 85 provider, 86 name, 87 gdcInputOperands!Args, 88 gdcInputOperandValues!Args, 89 ); 90 else version(LDC) 91 enum USDT_PROBE = USDT_PROBE_LDC.format( 92 provider, 93 name, 94 ldcInputOperands!Args, 95 ldcInputOperandConstraints!Args, 96 ldcInputOperandValues!Args, 97 ); 98 else version(DigitalMars) 99 enum USDT_PROBE = "{}"; 100 else 101 static assert(0, "Unsupported compiler"); 102 } 103 104 static this() 105 { 106 version(GNU) 107 { 108 109 } 110 else version(LDC) 111 { 112 113 } 114 else version(DigitalMars) 115 { 116 pragma(msg, "\t[usdt] Attention!"); 117 pragma(msg, "\t[usdt] Digital Mars compiler (dmd) does not support stap probes."); 118 pragma(msg, "\t[usdt] Stap probes are unavailable."); 119 } 120 } 121 122 // Helpers 123 124 private template ArgSize(Arg) 125 { 126 import std.traits : isSigned; 127 static if (isSigned!Arg) 128 enum ArgSize = cast(int) Arg.sizeof; 129 else 130 enum ArgSize = cast(int) -Arg.sizeof; 131 } 132 133 unittest 134 { 135 assert( ArgSize!int == 4 ); 136 assert( ArgSize!uint == -4 ); 137 } 138 139 private template gdcInputOperands(Args...) if (Args.length == 0) 140 { 141 enum gdcInputOperands = ""; 142 } 143 144 private template gdcInputOperands(Args...) if (Args.length) 145 { 146 import std.format : format; 147 static if (Args.length > 1) 148 enum fmt = "%%n[_SDT_S%1$d]@%%[_SDT_A%1$d] "; 149 else 150 enum fmt = "%%n[_SDT_S%1$d]@%%[_SDT_A%1$d]"; 151 152 enum gdcInputOperands = format(fmt, Args.length) ~ gdcInputOperands!(Args[1..$]); 153 } 154 155 unittest 156 { 157 void func(int a, int b) 158 { 159 int c; 160 assert( gdcInputOperands!() == "" ); 161 assert( gdcInputOperands!c == "%n[_SDT_S1]@%[_SDT_A1]" ); 162 assert( gdcInputOperands!(a, b) == "%n[_SDT_S2]@%[_SDT_A2] %n[_SDT_S1]@%[_SDT_A1]" ); 163 } 164 165 func(1, 2); 166 } 167 168 private template gdcInputOperandValues(Args...) if (Args.length == 0) 169 { 170 enum gdcInputOperandValues = ""; 171 } 172 173 private template gdcInputOperandValues(Args...) if (Args.length) 174 { 175 static if (Args.length > 1) 176 enum fmt = `[_SDT_S%1$d] "n" (%3$s), [_SDT_A%1$d] "nor" (%2$s), `; 177 else 178 enum fmt = `[_SDT_S%1$d] "n" (%3$s), [_SDT_A%1$d] "nor" (%2$s)`; 179 180 import std.format : format; 181 182 enum size = ArgSize!(typeof(Args[0])); 183 enum gdcInputOperandValues = 184 format(fmt, Args.length, __traits(identifier, Args[0]), size) ~ 185 gdcInputOperandValues!(Args[1..$]); 186 } 187 188 unittest 189 { 190 void func(int a, short b) 191 { 192 ubyte c; 193 assert( gdcInputOperandValues!() == "" ); 194 assert( gdcInputOperandValues!(c) == "[_SDT_S1] \"n\" (-1), [_SDT_A1] \"nor\" (c)" ); 195 assert( gdcInputOperandValues!(a, c) == "[_SDT_S2] \"n\" (4), [_SDT_A2] \"nor\" (a), [_SDT_S1] \"n\" (-1), [_SDT_A1] \"nor\" (c)" ); 196 assert( gdcInputOperandValues!(a, b, c) == "[_SDT_S3] \"n\" (4), [_SDT_A3] \"nor\" (a), [_SDT_S2] \"n\" (2), [_SDT_A2] \"nor\" (b), [_SDT_S1] \"n\" (-1), [_SDT_A1] \"nor\" (c)" ); 197 } 198 199 func(1, 2); 200 } 201 202 private template ldcInputOperands(Args...) if (Args.length == 0) 203 { 204 enum ldcInputOperands = ""; 205 } 206 207 private template ldcInputOperands(Args...) if (Args.length) 208 { 209 import std.format : format; 210 static if (Args.length > 1) 211 enum fmt = " ${%d:n}@${%d}"; 212 else 213 enum fmt = "${%d:n}@${%d}"; 214 215 enum i = (Args.length-1)*2; 216 enum ldcInputOperands = ldcInputOperands!(Args[1..$]) ~ format(fmt, i, i+1); 217 } 218 219 unittest 220 { 221 void func(int a, int b) 222 { 223 int c; 224 assert( ldcInputOperands!() == "" ); 225 assert( ldcInputOperands!(c) == "${0:n}@${1}" ); 226 assert( ldcInputOperands!(a, c) == "${0:n}@${1} ${2:n}@${3}" ); 227 } 228 229 func(1, 2); 230 } 231 232 private template ldcInputOperandConstraints(Args...) if (Args.length == 0) 233 { 234 enum ldcInputOperandConstraints = ""; 235 } 236 237 private template ldcInputOperandConstraints(Args...) if (Args.length) 238 { 239 static if (Args.length > 1) 240 enum prefix = "n, nor, "; 241 else 242 enum prefix = "n, nor"; 243 244 enum ldcInputOperandConstraints = prefix ~ ldcInputOperandConstraints!(Args[1..$]); 245 } 246 247 unittest 248 { 249 void func(int a, int b) 250 { 251 int c; 252 assert( ldcInputOperandConstraints!() == "" ); 253 assert( ldcInputOperandConstraints!(c) == "n, nor" ); 254 assert( ldcInputOperandConstraints!(a, c) == "n, nor, n, nor" ); 255 } 256 257 func(1, 2); 258 } 259 260 private template ldcInputOperandValues(Args...) if (Args.length == 0) 261 { 262 enum ldcInputOperandValues = ""; 263 } 264 265 private template ldcInputOperandValues(Args...) if (Args.length) 266 { 267 import std.format : format; 268 static if (Args.length > 1) 269 enum fmt = `%1$s, (%2$s), `; 270 else 271 enum fmt = `%1$s, (%2$s)`; 272 273 enum size = ArgSize!(typeof(Args[0])); 274 enum ldcInputOperandValues = format(fmt, size, __traits(identifier, Args[0])) ~ ldcInputOperandValues!(Args[1..$]); 275 } 276 277 unittest 278 { 279 void func(int a, short b) 280 { 281 ubyte c; 282 assert( ldcInputOperandValues!() == "" ); 283 assert( ldcInputOperandValues!(c) == "-1, (c)" ); 284 assert( ldcInputOperandValues!(a, c) == "4, (a), -1, (c)" ); 285 assert( ldcInputOperandValues!(a, b, c) == "4, (a), 2, (b), -1, (c)" ); 286 } 287 288 func(1, 2); 289 } 290 291 @safe @nogc nothrow pure 292 unittest 293 { 294 mixin USDT_PROBE!("unit", "test"); 295 }