%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(trace_nif_SUITE).
-include_lib("common_test/include/ct.hrl").
-export([all/0, suite/0]).
-export([trace_nif/1,
trace_nif_timestamp/1,
trace_nif_local/1,
trace_nif_meta/1,
trace_nif_timestamp_local/1,
trace_nif_return/1,
not_run/1]).
-export([nif_process/0, nif/0, nif/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
case test_server:is_native(trace_nif_SUITE) of
true -> [not_run];
false ->
[trace_nif, trace_nif_timestamp, trace_nif_local,
trace_nif_meta, trace_nif_timestamp_local,
trace_nif_return]
end.
not_run(Config) when is_list(Config) ->
{skipped,"Native code"}.
%% Test tracing NIFs.
trace_nif(Config) when is_list(Config) ->
load_nif(Config),
do_trace_nif([]).
%% Test tracing NIFs with local flag.
trace_nif_local(Config) when is_list(Config) ->
load_nif(Config),
do_trace_nif([local]).
%% Test tracing NIFs with meta flag.
trace_nif_meta(Config) when is_list(Config) ->
load_nif(Config),
Pid=spawn_link(?MODULE, nif_process, []),
erlang:trace_pattern({?MODULE,nif,'_'}, [], [meta]),
Pid ! {apply_nif, nif, []},
receive_trace_msg_ts({trace_ts,Pid,call,{?MODULE,nif,[]}}),
Pid ! {apply_nif, nif, ["Arg1"]},
receive_trace_msg_ts({trace_ts,Pid,call,
{?MODULE,nif, ["Arg1"]}}),
Pid ! {call_nif, nif, []},
receive_trace_msg_ts({trace_ts,Pid,call,
{?MODULE,nif, []}}),
Pid ! {call_nif, nif, ["Arg1"]},
receive_trace_msg_ts({trace_ts,Pid,call,
{?MODULE,nif, ["Arg1"]}}),
ok.
do_trace_nif(Flags) ->
Pid = spawn_link(?MODULE, nif_process, []),
1 = erlang:trace(Pid, true, [call]),
erlang:trace_pattern({?MODULE,nif,'_'}, [], Flags),
Pid ! {apply_nif, nif, []},
receive_trace_msg({trace,Pid,call,{?MODULE,nif, []}}),
Pid ! {apply_nif, nif, ["Arg1"]},
receive_trace_msg({trace,Pid,call,{?MODULE,nif, ["Arg1"]}}),
Pid ! {call_nif, nif, []},
receive_trace_msg({trace, Pid, call, {?MODULE,nif, []}}),
Pid ! {call_nif, nif, ["Arg1"]},
receive_trace_msg({trace, Pid, call, {?MODULE,nif, ["Arg1"]}}),
%% Switch off
1 = erlang:trace(Pid, false, [call]),
Pid ! {apply_nif, nif, []},
receive_nothing(),
Pid ! {apply_nif, nif, ["Arg1"]},
receive_nothing(),
Pid ! {call_nif, nif, []},
receive_nothing(),
Pid ! {call_nif, nif, ["Arg1"]},
receive_nothing(),
%% Switch on again
1 = erlang:trace(Pid, true, [call]),
erlang:trace_pattern({?MODULE,nif,'_'}, [], Flags),
Pid ! {apply_nif, nif, []},
receive_trace_msg({trace,Pid,call,{?MODULE,nif, []}}),
Pid ! {apply_nif, nif, ["Arg1"]},
receive_trace_msg({trace,Pid,call,{?MODULE,nif, ["Arg1"]}}),
Pid ! {call_nif, nif, []},
receive_trace_msg({trace, Pid, call, {?MODULE,nif, []}}),
Pid ! {call_nif, nif, ["Arg1"]},
receive_trace_msg({trace, Pid, call, {?MODULE,nif, ["Arg1"]}}),
1 = erlang:trace(Pid, false, [call]),
erlang:trace_pattern({?MODULE,nif,'_'}, false, Flags),
unlink(Pid),
exit(Pid, die),
ok.
%% Test tracing NIFs with timestamps.
trace_nif_timestamp(Config) when is_list(Config) ->
load_nif(Config),
do_trace_nif_timestamp([]).
%% Test tracing NIFs with timestamps and local flag.
trace_nif_timestamp_local(Config) when is_list(Config) ->
load_nif(Config),
do_trace_nif_timestamp([local]).
do_trace_nif_timestamp(Flags) ->
Pid = spawn_link(?MODULE, nif_process, []),
1 = erlang:trace(Pid, true, [call,timestamp]),
erlang:trace_pattern({?MODULE,nif,'_'}, [], Flags),
Pid ! {apply_nif, nif, []},
receive_trace_msg_ts({trace_ts,Pid,call,{?MODULE,nif,[]}}),
Pid ! {apply_nif, nif, ["Arg1"]},
receive_trace_msg_ts({trace_ts,Pid,call,
{?MODULE,nif, ["Arg1"]}}),
Pid ! {call_nif, nif, []},
receive_trace_msg_ts({trace_ts,Pid,call,
{?MODULE,nif, []}}),
Pid ! {call_nif, nif, ["Arg1"]},
receive_trace_msg_ts({trace_ts,Pid,call,
{?MODULE,nif, ["Arg1"]}}),
%% We should be able to turn off the timestamp.
1 = erlang:trace(Pid, false, [timestamp]),
Pid ! {call_nif, nif, []},
receive_trace_msg({trace,Pid,call,
{?MODULE,nif, []}}),
Pid ! {apply_nif, nif, ["tjoho"]},
receive_trace_msg({trace,Pid,call,
{?MODULE,nif, ["tjoho"]}}),
1 = erlang:trace(Pid, false, [call]),
erlang:trace_pattern({erlang,'_','_'}, false, Flags),
unlink(Pid),
exit(Pid, die),
ok.
%% Test tracing NIF's with return/return_to trace.
trace_nif_return(Config) when is_list(Config) ->
load_nif(Config),
Pid = spawn_link(?MODULE, nif_process, []),
1 = erlang:trace(Pid, true, [call,timestamp,return_to]),
erlang:trace_pattern({?MODULE,nif,'_'}, [{'_',[],[{return_trace}]}],
[local]),
Pid ! {apply_nif, nif, []},
receive_trace_msg_ts({trace_ts,Pid,call,{?MODULE,nif,[]}}),
receive_trace_msg_ts_return_from({trace_ts,Pid,return_from,
{?MODULE,nif,0}}),
receive_trace_msg_ts_return_to({trace_ts,Pid,return_to,
{?MODULE, nif_process,0}}),
Pid ! {call_nif, nif, ["Arg1"]},
receive_trace_msg_ts({trace_ts,Pid,call,
{?MODULE,nif, ["Arg1"]}}),
receive_trace_msg_ts_return_from({trace_ts,Pid,return_from,
{?MODULE,nif,1}}),
receive_trace_msg_ts_return_to({trace_ts,Pid,return_to,
{?MODULE, nif_process,0}}),
ok.
receive_trace_msg(Mess) ->
receive
Mess ->
ok;
Other ->
ct:fail("Expected: ~p,~nGot: ~p~n", [Mess, Other])
after 5000 ->
ct:fail("Expected: ~p,~nGot: timeout~n", [Mess])
end.
receive_nothing() ->
timeout = receive M -> M after 100 -> timeout end.
receive_trace_msg_ts({trace_ts, Pid, call, {M,F,A}}) ->
receive
{trace_ts, Pid, call, {M, F, A}, _Ts} ->
ok;
Other ->
ct:fail("Expected: {trace, ~p, call, {~p, ~p, ~p}, TimeStamp}},~n"
"Got: ~p~n", [Pid, M, F, A, Other])
after 5000 ->
ct:fail("Got timeout~n", [])
end.
receive_trace_msg_ts_return_from({trace_ts, Pid, return_from, {M,F,A}}) ->
receive
{trace_ts, Pid, return_from, {M, F, A}, _Value, _Ts} ->
ok;
Other ->
ct:fail("Expected: {trace_ts, ~p, return_from, {~p, ~p, ~p}, Value, TimeStamp}},~n"
"Got: ~p~n", [Pid, M, F, A, Other])
after 5000 ->
ct:fail("Got timeout~n", [])
end.
receive_trace_msg_ts_return_to({trace_ts, Pid, return_to, {M,F,A}}) ->
receive
{trace_ts, Pid, return_to, {M, F, A}, _Ts} ->
ok;
Other ->
ct:fail("Expected: {trace_ts, ~p, return_to, {~p, ~p, ~p}, TimeStamp}},~n"
"Got: ~p~n", [Pid, M, F, A, Other])
after 5000 ->
ct:fail("Got timeout~n", [])
end.
nif_process() ->
receive
{apply_nif, Name, Args} ->
{ok,Args} = apply(?MODULE, Name, Args);
{call_nif, Name, []} ->
{ok, []} = ?MODULE:Name();
{call_nif, Name, [A1]} ->
{ok, [A1]} = ?MODULE:Name(A1);
{call_nif, Name, [A1,A2]} ->
{ok,[A1,A2]} = ?MODULE:Name(A1,A2);
{call_nif, Name, [A1,A2,A3]} ->
{ok,[A1,A2,A3]} = ?MODULE:Name(A1,A2,A3)
end,
nif_process().
load_nif(Config) ->
case is_nif_loaded() of
true ->
ok;
false ->
Path = proplists:get_value(data_dir, Config),
ok = erlang:load_nif(filename:join(Path,"trace_nif"), 0)
end.
is_nif_loaded() ->
false.
nif() ->
{"Stub0",[]}. %exit("nif/0 stub called").
nif(A1) ->
{"Stub1",[A1]}. %exit(["nif/1 stub called",A1]).