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