1-module(dyntrace). 2 3%%% @doc The Dynamic tracing interface module 4%%% 5%%% This Dynamic tracing interface module, with the corresponding NIFs, should 6%%% work on any operating system platform where user-space DTrace/Systemtap 7%%% (and in the future LttNG UST) probes are supported. 8%%% 9%%% It is recommended that you use the `dyntrace:p()' function to add 10%%% Dynamic trace probes to your Erlang code. This function can accept up to 11%%% four integer arguments and four string arguments; the integer 12%%% argument(s) must come before any string argument. 13%%% 14%%% If using DTrace, enable the dynamic trace probe using the 'dtrace' 15%%% command, for example: 16%%% 17%%% dtrace -s /your/path/to/lib/runtime_tools-1.8.7/examples/user-probe.d 18%%% 19%%% Then, back at the Erlang shell, try this example: 20%%% ``` 21%%% 1> dyntrace:put_tag("GGOOOAAALL!!!!!"). 22%%% true 23%%% 24%%% 2> dyntrace:p(7, 8, 9, "one", "four"). 25%%% true 26%%% ''' 27%%% 28%%% Output from the example D script `user-probe.d' looks like: 29%%% ``` 30%%% <0.34.0> GGOOOAAALL!!!!! 7 8 9 0 'one' 'four' '' '' 31%%% ''' 32%%% 33%%% If the expected type of variable is not present, e.g. integer when 34%%% integer() is expected, or an I/O list when iolist() is expected, 35%%% then the driver will ignore the user's input and use a default 36%%% value of 0 or NULL, respectively. 37 38-export([available/0, 39 user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 40 p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8, 41 pn/1, pn/2, pn/3, pn/4, pn/5, pn/6, pn/7, pn/8, pn/9]). 42-export([put_tag/1, get_tag/0, get_tag_data/0, spread_tag/1, restore_tag/1]). 43 44-export([trace/5, 45 trace_procs/5, 46 trace_ports/5, 47 trace_running_procs/5, 48 trace_running_ports/5, 49 trace_call/5, 50 trace_send/5, 51 trace_receive/5, 52 trace_garbage_collection/5]). 53 54-export([enabled_procs/3, 55 enabled_ports/3, 56 enabled_running_procs/3, 57 enabled_running_ports/3, 58 enabled_call/3, 59 enabled_send/3, 60 enabled_receive/3, 61 enabled_garbage_collection/3, 62 enabled/3]). 63 64-export([user_trace_i4s4/9]). % Know what you're doing! 65-compile(no_native). 66-on_load(on_load/0). 67 68-type probe_arg() :: integer() | iolist(). 69-type int_p_arg() :: integer() | iolist() | undef. 70-type n_probe_label() :: 0..1023. 71 72%% The *_maybe() types use atom() instead of a stricter 'undef' 73%% because user_trace_i4s4/9 is exposed to the outside world, and 74%% because the driver will allow any atom to be used as a "not 75%% present" indication, we'll allow any atom in the types. 76 77-type integer_maybe() :: integer() | atom(). 78-type iolist_maybe() :: iolist() | atom(). 79 80on_load() -> 81 PrivDir = code:priv_dir(runtime_tools), 82 LibName = "dyntrace", 83 Lib = filename:join([PrivDir, "lib", LibName]), 84 Status = case erlang:load_nif(Lib, 0) of 85 ok -> ok; 86 {error, {load_failed, _}}=Error1 -> 87 ArchLibDir = 88 filename:join([PrivDir, "lib", 89 erlang:system_info(system_architecture)]), 90 Candidate = 91 filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])), 92 case Candidate of 93 [] -> Error1; 94 _ -> 95 ArchLib = filename:join([ArchLibDir, LibName]), 96 erlang:load_nif(ArchLib, 0) 97 end; 98 Error1 -> Error1 99 end, 100 case Status of 101 ok -> ok; 102 {error, {E, Str}} -> 103 case erlang:system_info(dynamic_trace) of 104 none -> 105 ok; 106 _ -> 107 error_logger:error_msg("Unable to load dyntrace library. Failed with error:~n 108\"~p, ~s\"~n" 109 "Dynamic tracing is enabled but the driver is not built correctly~n",[ 110 E,Str]), 111 Status 112 end 113 end. 114 115%%% 116%%% NIF placeholders 117%%% 118 119-spec available() -> true | false. 120 121available() -> 122 erlang:nif_error(nif_not_loaded). 123 124-spec user_trace_s1(iolist()) -> true | false | error | badarg. 125 126user_trace_s1(_Message) -> 127 erlang:nif_error(nif_not_loaded). 128 129-spec user_trace_i4s4(binary() | undefined, 130 integer_maybe(), integer_maybe(), 131 integer_maybe(), integer_maybe(), 132 iolist_maybe(), iolist_maybe(), 133 iolist_maybe(), iolist_maybe()) -> 134 true | false | error | badarg. 135 136user_trace_i4s4(_, _, _, _, _, _, _, _, _) -> 137 erlang:nif_error(nif_not_loaded). 138 139-spec user_trace_n(n_probe_label(), binary() | undefined, 140 integer_maybe(), integer_maybe(), 141 integer_maybe(), integer_maybe(), 142 iolist_maybe(), iolist_maybe(), 143 iolist_maybe(), iolist_maybe()) -> 144 true | false | error | badarg. 145 146user_trace_n(_, _, _, _, _, _, _, _, _, _) -> 147 erlang:nif_error(nif_not_loaded). 148 149trace(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 150 erlang:nif_error(nif_not_loaded). 151 152trace_procs(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 153 erlang:nif_error(nif_not_loaded). 154 155trace_ports(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 156 erlang:nif_error(nif_not_loaded). 157 158trace_running_procs(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 159 erlang:nif_error(nif_not_loaded). 160 161trace_running_ports(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 162 erlang:nif_error(nif_not_loaded). 163 164trace_call(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 165 erlang:nif_error(nif_not_loaded). 166 167trace_send(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 168 erlang:nif_error(nif_not_loaded). 169 170trace_receive(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 171 erlang:nif_error(nif_not_loaded). 172 173trace_garbage_collection(_TraceTag, _TracerState, _Tracee, _TraceTerm, _Opts) -> 174 erlang:nif_error(nif_not_loaded). 175 176enabled(_TraceTag, _TracerState, _Tracee) -> 177 erlang:nif_error(nif_not_loaded). 178 179enabled_procs(_TraceTag, _TracerState, _Tracee) -> 180 erlang:nif_error(nif_not_loaded). 181 182enabled_ports(_TraceTag, _TracerState, _Tracee) -> 183 erlang:nif_error(nif_not_loaded). 184 185enabled_running_procs(_TraceTag, _TracerState, _Tracee) -> 186 erlang:nif_error(nif_not_loaded). 187 188enabled_running_ports(_TraceTag, _TracerState, _Tracee) -> 189 erlang:nif_error(nif_not_loaded). 190 191enabled_call(_TraceTag, _TracerState, _Tracee) -> 192 erlang:nif_error(nif_not_loaded). 193 194enabled_send(_TraceTag, _TracerState, _Tracee) -> 195 erlang:nif_error(nif_not_loaded). 196 197enabled_receive(_TraceTag, _TracerState, _Tracee) -> 198 erlang:nif_error(nif_not_loaded). 199 200enabled_garbage_collection(_TraceTag, _TracerState, _Tracee) -> 201 erlang:nif_error(nif_not_loaded). 202 203%%% 204%%% Erlang support functions 205%%% 206 207-spec p() -> true | false | error | badarg. 208 209p() -> 210 user_trace_int(undef, undef, undef, undef, undef, undef, undef, undef). 211 212-spec p(probe_arg()) -> true | false | error | badarg. 213 214p(I1) when is_integer(I1) -> 215 user_trace_int(I1, undef, undef, undef, undef, undef, undef, undef); 216p(S1) -> 217 user_trace_int(undef, undef, undef, undef, S1, undef, undef, undef). 218 219-spec p(probe_arg(), probe_arg()) -> true | false | error | badarg. 220 221p(I1, I2) when is_integer(I1), is_integer(I2) -> 222 user_trace_int(I1, I2, undef, undef, undef, undef, undef, undef); 223p(I1, S1) when is_integer(I1) -> 224 user_trace_int(I1, undef, undef, undef, S1, undef, undef, undef); 225p(S1, S2) -> 226 user_trace_int(undef, undef, undef, undef, S1, S2, undef, undef). 227 228-spec p(probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg. 229 230p(I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) -> 231 user_trace_int(I1, I2, I3, undef, undef, undef, undef, undef); 232p(I1, I2, S1) when is_integer(I1), is_integer(I2) -> 233 user_trace_int(I1, I2, undef, undef, S1, undef, undef, undef); 234p(I1, S1, S2) when is_integer(I1) -> 235 user_trace_int(I1, undef, undef, undef, S1, S2, undef, undef); 236p(S1, S2, S3) -> 237 user_trace_int(undef, undef, undef, undef, S1, S2, S3, undef). 238 239-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> 240 true | false | error | badarg. 241 242p(I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 243 user_trace_int(I1, I2, I3, I4, undef, undef, undef, undef); 244p(I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) -> 245 user_trace_int(I1, I2, I3, undef, S1, undef, undef, undef); 246p(I1, I2, S1, S2) when is_integer(I1), is_integer(I2) -> 247 user_trace_int(I1, I2, undef, undef, S1, S2, undef, undef); 248p(I1, S1, S2, S3) when is_integer(I1) -> 249 user_trace_int(I1, undef, undef, undef, S1, S2, S3, undef); 250p(S1, S2, S3, S4) -> 251 user_trace_int(undef, undef, undef, undef, S1, S2, S3, S4). 252 253-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), 254 probe_arg()) -> 255 true | false | error | badarg. 256 257p(I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 258 user_trace_int(I1, I2, I3, I4, S1, undef, undef, undef); 259p(I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) -> 260 user_trace_int(I1, I2, I3, undef, S1, S2, undef, undef); 261p(I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) -> 262 user_trace_int(I1, I2, undef, undef, S1, S2, S3, undef); 263p(I1, S1, S2, S3, S4) when is_integer(I1) -> 264 user_trace_int(I1, undef, undef, undef, S1, S2, S3, S4). 265 266-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), 267 probe_arg(), probe_arg()) -> 268 true | false | error | badarg. 269 270p(I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 271 user_trace_int(I1, I2, I3, I4, S1, S2, undef, undef); 272p(I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) -> 273 user_trace_int(I1, I2, I3, undef, S1, S2, S3, undef); 274p(I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) -> 275 user_trace_int(I1, I2, undef, undef, S1, S2, S3, S4). 276 277-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), 278 probe_arg(), probe_arg(), probe_arg()) -> 279 true | false | error | badarg. 280 281p(I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 282 user_trace_int(I1, I2, I3, I4, S1, S2, S3, undef); 283p(I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) -> 284 user_trace_int(I1, I2, I3, undef, S1, S2, S3, S4). 285 286-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), 287 probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> 288 true | false | error | badarg. 289 290p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 291 user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4). 292 293-spec user_trace_int(int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(), 294 int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) -> 295 true | false | error | badarg. 296 297user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> 298 UTag = get_tag(), 299 try 300 user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4) 301 catch 302 error:nif_not_loaded -> 303 false 304 end. 305 306-spec pn(n_probe_label()) -> true | false | error | badarg. 307 308pn(ProbeLabel) -> 309 user_trace_n_int(ProbeLabel, undef, undef, undef, undef, undef, undef, undef, undef). 310 311-spec pn(n_probe_label(), probe_arg()) -> true | false | error | badarg. 312 313pn(ProbeLabel, I1) when is_integer(I1) -> 314 user_trace_n_int(ProbeLabel, I1, undef, undef, undef, undef, undef, undef, undef); 315pn(ProbeLabel, S1) -> 316 user_trace_n_int(ProbeLabel, undef, undef, undef, undef, S1, undef, undef, undef). 317 318-spec pn(n_probe_label(), probe_arg(), probe_arg()) -> true | false | error | badarg. 319 320pn(ProbeLabel, I1, I2) when is_integer(I1), is_integer(I2) -> 321 user_trace_n_int(ProbeLabel, I1, I2, undef, undef, undef, undef, undef, undef); 322pn(ProbeLabel, I1, S1) when is_integer(I1) -> 323 user_trace_n_int(ProbeLabel, I1, undef, undef, undef, S1, undef, undef, undef); 324pn(ProbeLabel, S1, S2) -> 325 user_trace_n_int(ProbeLabel, undef, undef, undef, undef, S1, S2, undef, undef). 326 327-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg. 328 329pn(ProbeLabel, I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) -> 330 user_trace_n_int(ProbeLabel, I1, I2, I3, undef, undef, undef, undef, undef); 331pn(ProbeLabel, I1, I2, S1) when is_integer(I1), is_integer(I2) -> 332 user_trace_n_int(ProbeLabel, I1, I2, undef, undef, S1, undef, undef, undef); 333pn(ProbeLabel, I1, S1, S2) when is_integer(I1) -> 334 user_trace_n_int(ProbeLabel, I1, undef, undef, undef, S1, S2, undef, undef); 335pn(ProbeLabel, S1, S2, S3) -> 336 user_trace_n_int(ProbeLabel, undef, undef, undef, undef, S1, S2, S3, undef). 337 338-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> 339 true | false | error | badarg. 340 341pn(ProbeLabel, I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 342 user_trace_n_int(ProbeLabel, I1, I2, I3, I4, undef, undef, undef, undef); 343pn(ProbeLabel, I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) -> 344 user_trace_n_int(ProbeLabel, I1, I2, I3, undef, S1, undef, undef, undef); 345pn(ProbeLabel, I1, I2, S1, S2) when is_integer(I1), is_integer(I2) -> 346 user_trace_n_int(ProbeLabel, I1, I2, undef, undef, S1, S2, undef, undef); 347pn(ProbeLabel, I1, S1, S2, S3) when is_integer(I1) -> 348 user_trace_n_int(ProbeLabel, I1, undef, undef, undef, S1, S2, S3, undef); 349pn(ProbeLabel, S1, S2, S3, S4) -> 350 user_trace_n_int(ProbeLabel, undef, undef, undef, undef, S1, S2, S3, S4). 351 352-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg(), 353 probe_arg()) -> 354 true | false | error | badarg. 355 356pn(ProbeLabel, I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 357 user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, undef, undef, undef); 358pn(ProbeLabel, I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) -> 359 user_trace_n_int(ProbeLabel, I1, I2, I3, undef, S1, S2, undef, undef); 360pn(ProbeLabel, I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) -> 361 user_trace_n_int(ProbeLabel, I1, I2, undef, undef, S1, S2, S3, undef); 362pn(ProbeLabel, I1, S1, S2, S3, S4) when is_integer(I1) -> 363 user_trace_n_int(ProbeLabel, I1, undef, undef, undef, S1, S2, S3, S4). 364 365-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg(), 366 probe_arg(), probe_arg()) -> 367 true | false | error | badarg. 368 369pn(ProbeLabel, I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 370 user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, S2, undef, undef); 371pn(ProbeLabel, I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) -> 372 user_trace_n_int(ProbeLabel, I1, I2, I3, undef, S1, S2, S3, undef); 373pn(ProbeLabel, I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) -> 374 user_trace_n_int(ProbeLabel, I1, I2, undef, undef, S1, S2, S3, S4). 375 376-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg(), 377 probe_arg(), probe_arg(), probe_arg()) -> 378 true | false | error | badarg. 379 380pn(ProbeLabel, I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 381 user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, S2, S3, undef); 382pn(ProbeLabel, I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) -> 383 user_trace_n_int(ProbeLabel, I1, I2, I3, undef, S1, S2, S3, S4). 384 385-spec pn(n_probe_label(), probe_arg(), probe_arg(), probe_arg(), probe_arg(), 386 probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> 387 true | false | error | badarg. 388 389pn(ProbeLabel, I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> 390 user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, S2, S3, S4). 391 392-spec user_trace_n_int(n_probe_label(), 393 int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(), 394 int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) -> 395 true | false | error | badarg. 396 397user_trace_n_int(ProbeLabel, I1, I2, I3, I4, S1, S2, S3, S4) -> 398 UTag = get_tag(), 399 try 400 user_trace_n(ProbeLabel, UTag, I1, I2, I3, I4, S1, S2, S3, S4) 401 catch 402 error:nif_not_loaded -> 403 false 404 end. 405 406-spec put_tag(undefined | iodata()) -> binary() | undefined. 407put_tag(Data) -> 408 erlang:dt_put_tag(unicode:characters_to_binary(Data)). 409 410-spec get_tag() -> binary() | undefined. 411get_tag() -> 412 erlang:dt_get_tag(). 413 414-spec get_tag_data() -> binary() | undefined. 415%% Gets tag if set, otherwise the spread tag data from last incoming message 416get_tag_data() -> 417 erlang:dt_get_tag_data(). 418 419-spec spread_tag(boolean()) -> true | {non_neg_integer(), binary() | []}. 420%% Makes the tag behave as a sequential trace token, will spread with 421%% messages to be picked up by someone using get_tag_data 422spread_tag(B) -> 423 erlang:dt_spread_tag(B). 424 425-spec restore_tag(true | {non_neg_integer(), binary() | []}) -> true. 426restore_tag(T) -> 427 erlang:dt_restore_tag(T). 428