1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(trace_local_SUITE).
22
23-export([basic_test/0, bit_syntax_test/0, return_test/0,
24	 on_and_off_test/0, stack_grow_test/0,
25	 info_test/0, delete_test/1, exception_test/1,
26	 not_run/1]).
27
28-export([exported/1, exported_wrap/1, loop/4, apply_slave_async/5,
29	 match/2, clause/2, id/1, undef/1, lists_reverse/2]).
30
31
32%%
33%% Define for debug output
34%%
35%%-define(debug,1).
36
37-include_lib("common_test/include/ct.hrl").
38-define(DEFAULT_RECEIVE_TIMEOUT, infinity).
39
40-ifdef(debug).
41-define(dbgformat(A,B),io:format(A,B)).
42-else.
43-define(dbgformat(A,B),noop).
44-endif.
45
46%%% When run in test server %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
47
48-export([all/0, suite/0,
49         basic/1, bit_syntax/1,
50         return/1, on_and_off/1, systematic_on_off/1,
51         stack_grow/1,info/1, delete/1,
52         exception/1, exception_apply/1,
53         exception_function/1, exception_apply_function/1,
54         exception_nocatch/1, exception_nocatch_apply/1,
55         exception_nocatch_function/1, exception_nocatch_apply_function/1,
56         exception_meta/1, exception_meta_apply/1,
57         exception_meta_function/1, exception_meta_apply_function/1,
58         exception_meta_nocatch/1, exception_meta_nocatch_apply/1,
59         exception_meta_nocatch_function/1,
60         exception_meta_nocatch_apply_function/1,
61         concurrency/1,
62         init_per_testcase/2, end_per_testcase/2]).
63
64init_per_testcase(_Case, Config) ->
65    Config.
66
67end_per_testcase(_Case, _Config) ->
68    shutdown(),
69
70    %% Reloading the module will clear all trace patterns, and
71    %% in a debug-compiled emulator run assertions of the counters
72    %% for the number of functions with breakpoints.
73
74    c:l(?MODULE).
75
76suite() ->
77    [{ct_hooks,[ts_install_cth]},
78     {timetrap, {minutes, 2}}].
79
80all() ->
81    case test_server:is_native(trace_local_SUITE) of
82        true -> [not_run];
83        false ->
84            [basic, bit_syntax, return, on_and_off, systematic_on_off,
85             stack_grow,
86             info, delete, exception, exception_apply,
87             exception_function, exception_apply_function,
88             exception_nocatch, exception_nocatch_apply,
89             exception_nocatch_function,
90             exception_nocatch_apply_function, exception_meta,
91             exception_meta_apply, exception_meta_function,
92             exception_meta_apply_function, exception_meta_nocatch,
93             exception_meta_nocatch_apply,
94             exception_meta_nocatch_function,
95             exception_meta_nocatch_apply_function,
96             concurrency]
97    end.
98
99
100not_run(Config) when is_list(Config) ->
101    {skipped,"Native code"}.
102
103%% Tests basic local call-trace
104basic(Config) when is_list(Config) ->
105    basic_test().
106
107%% OTP-7399: Make sure that code that uses the optimized bit syntax matching
108%% can be traced without crashing the emulator.
109bit_syntax(Config) when is_list(Config) ->
110    bit_syntax_test().
111
112%% Tests the different types of return trace
113return(Config) when is_list(Config) ->
114    return_test().
115
116%% Tests turning trace parameters on and off,
117%% both for trace and trace_pattern
118on_and_off(Config) when is_list(Config) ->
119    on_and_off_test().
120
121%% Tests the stack growth during return traces
122stack_grow(Config) when is_list(Config) ->
123    stack_grow_test().
124
125%% Tests the trace_info BIF
126info(Config) when is_list(Config) ->
127    info_test().
128
129%% Tests putting trace on deleted modules
130delete(Config) when is_list(Config) ->
131    delete_test(Config).
132
133%% Tests exception_trace
134exception(Config) when is_list(Config) ->
135    exception_test([]).
136
137%% Tests exception_trace
138exception_apply(Config) when is_list(Config) ->
139    exception_test([apply]).
140
141%% Tests exception_trace
142exception_function(Config) when is_list(Config) ->
143    exception_test([function]).
144
145%% Tests exception_trace
146exception_apply_function(Config) when is_list(Config) ->
147    exception_test([apply,function]).
148
149%% Tests exception_trace
150exception_nocatch(Config) when is_list(Config) ->
151    exception_test([nocatch]).
152
153%% Tests exception_trace
154exception_nocatch_apply(Config) when is_list(Config) ->
155    exception_test([nocatch,apply]).
156
157%% Tests exception_trace
158exception_nocatch_function(Config) when is_list(Config) ->
159    exception_test([nocatch,function]).
160
161%% Tests exception_trace
162exception_nocatch_apply_function(Config) when is_list(Config) ->
163    exception_test([nocatch,apply,function]).
164
165%% Tests meta exception_trace
166exception_meta(Config) when is_list(Config) ->
167    exception_test([meta]).
168
169%% Tests meta exception_trace
170exception_meta_apply(Config) when is_list(Config) ->
171    exception_test([meta,apply]).
172
173%% Tests meta exception_trace
174exception_meta_function(Config) when is_list(Config) ->
175    exception_test([meta,function]).
176
177%% Tests meta exception_trace
178exception_meta_apply_function(Config) when is_list(Config) ->
179    exception_test([meta,apply,function]).
180
181%% Tests meta exception_trace
182exception_meta_nocatch(Config) when is_list(Config) ->
183    exception_test([meta,nocatch]).
184
185%% Tests meta exception_trace
186exception_meta_nocatch_apply(Config) when is_list(Config) ->
187    exception_test([meta,nocatch,apply]).
188
189%% Tests meta exception_trace
190exception_meta_nocatch_function(Config) when is_list(Config) ->
191    exception_test([meta,nocatch,function]).
192
193%% Tests meta exception_trace
194exception_meta_nocatch_apply_function(Config) when is_list(Config) ->
195    exception_test([meta,nocatch,apply,function]).
196
197
198%%% Message patterns and expect functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199
200-define(pCT(P,M,F,A),   {trace,   P,call,{M,F,A}}).
201-define(pCTT(P,M,F,A),  {trace_ts,P,call,{M,F,A},{_,_,_}}).
202-define(pRF(P,M,F,A,V), {trace,   P,return_from,{M,F,A},V}).
203-define(pRFT(P,M,F,A,V),{trace_ts,P,return_from,{M,F,A},V,{_,_,_}}).
204-define(pEF(P,M,F,A,V), {trace,   P,exception_from,{M,F,A},V}).
205-define(pEFT(P,M,F,A,V),{trace_ts,P,exception_from,{M,F,A},V,{_,_,_}}).
206-define(pRT(P,M,F,A),   {trace,   P,return_to,{M,F,A}}).
207-define(pRTT(P,M,F,A),  {trace_ts,P,return_to,{M,F,A},{_,_,_}}).
208
209-define(CT(M,F,A),    ?pCT(_,M,F,A)    = receive_next()).
210-define(CTT(M,F,A),   ?pCTT(_,M,F,A)   = receive_next()).
211-define(RF(M,F,A,V),  ?pRF(_,M,F,A,V)  = receive_next()).
212-define(RFT(M,F,A,V), ?pRFT(_,M,F,A,V) = receive_next()).
213-define(EF(M,F,A,V),  ?pEF(_,M,F,A,V)  = receive_next()).
214-define(EFT(M,F,A,V), ?pEFT(_,M,F,A,V) = receive_next()).
215-define(RT(M,F,A),    ?pRT(_,M,F,A)    = receive_next()).
216-define(RTT(M,F,A),   ?pRTT(_,M,F,A)   = receive_next()).
217-define(NM, receive_no_next(100)).
218
219expect() ->
220    {Pid,_} = get(slave),
221    expect_receive(Pid).
222
223expect(Msg) ->
224    {Pid,_} = get(slave),
225    expect_pid(Pid, Msg).
226
227
228
229expect_pid(_Pid, []) ->
230    ok;
231expect_pid(Pid, [Line|T]) when is_integer(Line) ->
232    put(test_server_loc, {?MODULE,Line}),
233    expect_pid(Pid, T);
234expect_pid(Pid, [true|[_|_]=T]) ->
235    expect_pid(Pid, T);
236expect_pid(Pid, [false|[_|T]]) ->
237    expect_pid(Pid, T);
238expect_pid(Pid, [H|T]) ->
239    expect_pid(Pid, H),
240    expect_pid(Pid, T);
241expect_pid(Pid, Msg) when is_tuple(Msg) ->
242    same(Msg, expect_receive(Pid));
243expect_pid(Pid, Fun) when is_function(Fun, 1) ->
244    case Fun(expect_receive(Pid)) of
245        next ->
246            expect_pid(Pid, Fun);
247        done ->
248            ok;
249        Other ->
250            expect_pid(Pid, Other)
251    end.
252
253expect_receive(Pid) when is_pid(Pid) ->
254    receive
255        Msg when is_tuple(Msg),
256                 element(1, Msg) == trace,
257                 element(2, Msg) =/= Pid;
258                 %%
259                 is_tuple(Msg),
260                 element(1, Msg) == trace_ts,
261                 element(2, Msg) =/= Pid ->
262            expect_receive(Pid);
263        Msg ->
264            expect_msg(Pid, Msg)
265    after 100 ->
266              {nm}
267    end.
268
269expect_msg(P, ?pCT(P,M,F,Args))       -> {ct,{M,F},Args};
270expect_msg(P, ?pCTT(P,M,F,Args))      -> {ctt,{M,F},Args};
271expect_msg(P, ?pRF(P,M,F,Arity,V))    -> {rf,{M,F,Arity},V};
272expect_msg(P, ?pRFT(P,M,F,Arity,V))   -> {rft,{M,F,Arity},V};
273expect_msg(P, ?pEF(P,M,F,Arity,V))    -> {ef,{M,F,Arity},V};
274expect_msg(P, ?pEFT(P,M,F,Arity,V))   -> {eft,{M,F,Arity},V};
275expect_msg(P, ?pRT(P,M,F,Arity))      -> {rt,{M,F,Arity}};
276expect_msg(P, ?pRTT(P,M,F,Arity))     -> {rtt,{M,F,Arity}};
277expect_msg(P, Msg) when is_tuple(Msg) ->
278    case tuple_to_list(Msg) of
279        [trace,P|T] ->
280            list_to_tuple([trace|T]);
281        [trace_ts,P|[_|_]=T] ->
282            list_to_tuple([trace_ts|reverse(tl(reverse(T)))]);
283        _ ->
284            Msg
285    end.
286
287same(A, B) ->
288    case [A|B] of
289        [X|X] ->
290            ok
291    end.
292
293
294
295%%% tests %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296
297basic_test() ->
298    setup([call]),
299    NumMatches = erlang:trace_pattern({?MODULE,'_','_'},[],[local]),
300    NumMatches = erlang:trace_pattern({?MODULE,'_','_'},[],[local]),
301    false = code:is_module_native(?MODULE), % got fooled by local trace
302    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
303    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
304    ?CT(?MODULE,exported_wrap,[1]),
305    ?CT(?MODULE,exported,[1]),
306    ?CT(?MODULE,local,[1]),
307    ?CT(?MODULE,local2,[1]),
308    ?CT(?MODULE,local_tail,[1]),
309    erlang:trace_pattern({?MODULE,'_','_'},[],[]),
310    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
311    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
312    ?CT(?MODULE,exported_wrap,[1]),
313    [1,1,1,997] = lambda_slave(fun() ->
314                                       exported_wrap(1)
315                               end),
316    ?NM,
317    erlang:trace_pattern({?MODULE,'_','_'},[],[local]),
318    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
319    [1,1,1,997] = lambda_slave(fun() ->
320                                       exported_wrap(1)
321                               end),
322    ?CT(?MODULE,_,_), %% The fun
323    ?CT(?MODULE,exported_wrap,[1]),
324    ?CT(?MODULE,exported,[1]),
325    ?CT(?MODULE,local,[1]),
326    ?CT(?MODULE,local2,[1]),
327    ?CT(?MODULE,local_tail,[1]),
328    erlang:trace_pattern({?MODULE,'_','_'},false,[local]),
329    shutdown(),
330    ?NM,
331    ok.
332
333%% OTP-7399.
334bit_syntax_test() ->
335    setup([call]),
336    erlang:trace_pattern({?MODULE,'_','_'},[],[local]),
337    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
338
339    lambda_slave(fun() ->
340                         6 = bs_sum_a(<<1,2,3>>, 0),
341                         10 = bs_sum_b(0, <<1,2,3,4>>),
342                         26 = bs_sum_c(<<3:4,5:4,7:4,11:4>>, 0)
343                 end),
344    ?CT(?MODULE,_,[]),		      %Ignore call to the fun.
345
346    ?CT(?MODULE,bs_sum_a,[<<1,2,3>>,0]),
347    ?CT(?MODULE,bs_sum_a,[<<2,3>>,1]),
348    ?CT(?MODULE,bs_sum_a,[<<3>>,3]),
349    ?CT(?MODULE,bs_sum_a,[<<>>,6]),
350
351    ?CT(?MODULE,bs_sum_b,[0,<<1,2,3,4>>]),
352    ?CT(?MODULE,bs_sum_b,[1,<<2,3,4>>]),
353    ?CT(?MODULE,bs_sum_b,[3,<<3,4>>]),
354    ?CT(?MODULE,bs_sum_b,[6,<<4>>]),
355    ?CT(?MODULE,bs_sum_b,[10,<<>>]),
356
357    ?CT(?MODULE,bs_sum_c,[<<3:4,5:4,7:4,11:4>>, 0]),
358    ?CT(?MODULE,bs_sum_c,[<<5:4,7:4,11:4>>, 3]),
359    ?CT(?MODULE,bs_sum_c,[<<7:4,11:4>>, 8]),
360    ?CT(?MODULE,bs_sum_c,[<<11:4>>, 15]),
361    ?CT(?MODULE,bs_sum_c,[<<>>, 26]),
362
363    erlang:trace_pattern({?MODULE,'_','_'},false,[local]),
364    shutdown(),
365    ?NM,
366
367    ok.
368
369bs_sum_a(<<H,T/binary>>, Acc) -> bs_sum_a(T, H+Acc);
370bs_sum_a(<<>>, Acc) -> Acc.
371
372bs_sum_b(Acc, <<H,T/binary>>) -> bs_sum_b(H+Acc, T);
373bs_sum_b(Acc, <<>>) -> Acc.
374
375bs_sum_c(<<H:4,T/bits>>, Acc) -> bs_sum_c(T, H+Acc);
376bs_sum_c(<<>>, Acc) -> Acc.
377
378return_test() ->
379    setup([call]),
380    erlang:trace_pattern({?MODULE,'_','_'},[{'_',[],[{return_trace}]}],
381                         [local]),
382    erlang:trace_pattern({erlang,phash2,'_'},[{'_',[],[{return_trace}]}],
383                         [local]),
384    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
385    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
386    ?CT(?MODULE,exported_wrap,[1]),
387    ?CT(?MODULE,exported,[1]),
388    ?CT(?MODULE,local,[1]),
389    ?CT(?MODULE,local2,[1]),
390    ?CT(?MODULE,local_tail,[1]),
391    ?CT(erlang,phash2,[1,1023]),
392    ?RF(erlang,phash2,2,997),
393    ?RF(?MODULE,local_tail,1,[1,997]),
394    ?RF(?MODULE,local2,1,[1,997]),
395    ?RF(?MODULE,local,1,[1,1,997]),
396    ?RF(?MODULE,exported,1,[1,1,1,997]),
397    ?RF(?MODULE,exported_wrap,1,[1,1,1,997]),
398    shutdown(),
399    setup([call,return_to]),
400    erlang:trace_pattern({?MODULE,'_','_'},[],
401                         [local]),
402    erlang:trace_pattern({erlang,phash2,'_'},[],
403                         [local]),
404    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
405    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
406    ?CT(?MODULE,exported_wrap,[1]),
407    ?CT(?MODULE,exported,[1]),
408    ?CT(?MODULE,local,[1]),
409    ?CT(?MODULE,local2,[1]),
410    ?CT(?MODULE,local_tail,[1]),
411    ?CT(erlang,phash2,[1,1023]),
412    ?RT(?MODULE,local_tail,1),
413    ?RT(?MODULE,local,1),
414    ?RT(?MODULE,exported,1),
415    ?RT(?MODULE,slave,2),
416    shutdown(),
417    setup([call,return_to]),
418    erlang:trace_pattern({?MODULE,'_','_'},[{'_',[],[{return_trace}]}],
419                         [local]),
420    erlang:trace_pattern({erlang,phash2,'_'},[{'_',[],[{return_trace}]}],
421                         [local]),
422    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
423    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
424    ?CT(?MODULE,exported_wrap,[1]),
425    ?CT(?MODULE,exported,[1]),
426    ?CT(?MODULE,local,[1]),
427    ?CT(?MODULE,local2,[1]),
428    ?CT(?MODULE,local_tail,[1]),
429    ?CT(erlang,phash2,[1,1023]),
430    ?RF(erlang,phash2,2,997),
431    ?RT(?MODULE,local_tail,1),
432    ?RF(?MODULE,local_tail,1,[1,997]),
433    ?RF(?MODULE,local2,1,[1,997]),
434    ?RT(?MODULE,local,1),
435    ?RF(?MODULE,local,1,[1,1,997]),
436    ?RT(?MODULE,exported,1),
437    ?RF(?MODULE,exported,1,[1,1,1,997]),
438    ?RF(?MODULE,exported_wrap,1,[1,1,1,997]),
439    ?RT(?MODULE,slave,2),
440    shutdown(),
441    ?NM,
442
443    %% Test a regression where turning off return_to tracing
444    %% on yourself would cause a segfault.
445    Pid = setup([call,return_to]),
446    erlang:trace_pattern({'_','_','_'},[],[local]),
447    apply_slave(erlang,trace,[Pid, false, [all]]),
448    shutdown(),
449    ok.
450
451on_and_off_test() ->
452    Pid = setup([call]),
453    1 = erlang:trace_pattern({?MODULE,local_tail,1},[],[local]),
454    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
455    LocalTail = fun() ->
456                        local_tail(1)
457                end,
458    [1,997] = lambda_slave(LocalTail),
459    ?CT(?MODULE,local_tail,[1]),
460    erlang:trace(Pid,true,[return_to]),
461    [1,997] = lambda_slave(LocalTail),
462    ?CT(?MODULE,local_tail,[1]),
463    ?RT(?MODULE,_,_),
464    0 = erlang:trace_pattern({?MODULE,local_tail,1},[],[global]),
465    [1,997] = lambda_slave(LocalTail),
466    ?NM,
467    1 = erlang:trace_pattern({?MODULE,exported_wrap,1},[],[global]),
468    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
469    ?CT(?MODULE,exported_wrap,[1]),
470    1 = erlang:trace_pattern({?MODULE,exported_wrap,1},[],[local]),
471    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
472    ?CT(?MODULE,exported_wrap,[1]),
473    ?RT(?MODULE,slave,2),
474    1 = erlang:trace_pattern({erlang,phash2,2},[],[local]),
475    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
476    ?CT(?MODULE,exported_wrap,[1]),
477    ?CT(erlang,phash2,[1,1023]),
478    ?RT(?MODULE,local_tail,1),
479    ?RT(?MODULE,slave,2),
480    erlang:trace(Pid,true,[timestamp]),
481    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
482    ?CTT(?MODULE,exported_wrap,[1]),
483    ?CTT(erlang,phash2,[1,1023]),
484    ?RTT(?MODULE,local_tail,1),
485    ?RTT(?MODULE,slave,2),
486    erlang:trace(Pid,false,[return_to,timestamp]),
487    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
488    ?CT(?MODULE,exported_wrap,[1]),
489    ?CT(erlang,phash2,[1,1023]),
490    erlang:trace(Pid,true,[return_to]),
491    1 = erlang:trace_pattern({erlang,phash2,2},[],[]),
492    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
493    ?CT(?MODULE,exported_wrap,[1]),
494    ?CT(erlang,phash2,[1,1023]),
495    ?RT(?MODULE,slave,2),
496    1 = erlang:trace_pattern({?MODULE,exported_wrap,1},[],[]),
497    [1,1,1,997] = apply_slave(?MODULE,exported_wrap,[1]),
498    ?CT(?MODULE,exported_wrap,[1]),
499    ?CT(erlang,phash2,[1,1023]),
500    shutdown(),
501    erlang:trace_pattern({'_','_','_'},false,[local]),
502    N = erlang:trace_pattern({erlang,'_','_'},true,[local]),
503    case erlang:trace_pattern({erlang,'_','_'},false,[local]) of
504        N ->
505            ok;
506        Else ->
507            exit({number_mismatch, {expected, N}, {got, Else}})
508    end,
509    case erlang:trace_pattern({erlang,'_','_'},false,[local]) of
510        N ->
511            ok;
512        Else2 ->
513            exit({number_mismatch, {expected, N}, {got, Else2}})
514    end,
515    M = erlang:trace_pattern({erlang,'_','_'},true,[]),
516    case erlang:trace_pattern({erlang,'_','_'},false,[]) of
517        M ->
518            ok;
519        Else3 ->
520            exit({number_mismatch, {expected, N}, {got, Else3}})
521    end,
522    case erlang:trace_pattern({erlang,'_','_'},false,[]) of
523        M ->
524            ok;
525        Else4 ->
526            exit({number_mismatch, {expected, N}, {got, Else4}})
527    end,
528    ?NM,
529    ok.
530
531systematic_on_off(Config) when is_list(Config) ->
532    setup([call]),
533    Local = combinations([local,meta,call_count,call_time]),
534    [systematic_on_off_1(Flags) || Flags <- Local],
535
536    %% Make sure that we don't get any trace messages when trace
537    %% is supposed to be off.
538    receive_no_next(500).
539
540systematic_on_off_1(Local) ->
541    io:format("~p\n", [Local]),
542
543    %% Global off.
544    verify_trace_info(false, []),
545    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, true, Local),
546    verify_trace_info(false, Local),
547    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, false, [global]),
548    verify_trace_info(false, Local),
549    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, false, Local),
550    verify_trace_info(false, []),
551
552    %% Global on.
553    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, true, [global]),
554    verify_trace_info(true, []),
555    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, false, Local),
556    verify_trace_info(true, []),
557    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, false, [global]),
558    verify_trace_info(false, []),
559
560    %% Implicitly turn off global call trace.
561    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, true, [global]),
562    verify_trace_info(true, []),
563    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, true, Local),
564    verify_trace_info(false, Local),
565
566    %% Implicitly turn off local call trace.
567    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, true, [global]),
568    verify_trace_info(true, []),
569
570    %% Turn off global call trace. Everything should be off now.
571    1 = erlang:trace_pattern({?MODULE,exported_wrap,1}, false, [global]),
572    verify_trace_info(false, []),
573
574    ok.
575
576verify_trace_info(Global, Local) ->
577    case erlang:trace_info({?MODULE,exported_wrap,1}, all) of
578        {all,false} ->
579            false = Global,
580            [] = Local;
581        {all,Ps} ->
582            io:format("~p\n", [Ps]),
583            [verify_trace_info(P, Global, Local) || P <- Ps]
584    end,
585    global_call(Global, Local),
586    local_call(Local),
587    ok.
588
589verify_trace_info({traced,global}, true, []) -> ok;
590verify_trace_info({traced,local}, false, _) -> ok;
591verify_trace_info({match_spec,[]}, _, _) -> ok;
592verify_trace_info({meta_match_spec,[]}, _, _) -> ok;
593verify_trace_info({LocalFlag,Bool}, _, Local) when is_boolean(Bool) ->
594    try
595        Bool = lists:member(LocalFlag, Local)
596    catch
597        error:_ ->
598            ct:fail("Line ~p: {~p,~p}, false, ~p\n", [?LINE,LocalFlag,Bool,Local])
599    end;
600verify_trace_info({meta,Pid}, false, Local) when is_pid(Pid) ->
601    true = lists:member(meta, Local);
602verify_trace_info({call_time,_}, false, Local) ->
603    true = lists:member(call_time, Local);
604verify_trace_info({call_count,_}, false, Local) ->
605    true = lists:member(call_time, Local).
606
607global_call(Global, Local) ->
608    apply_slave(?MODULE, exported_wrap, [global_call]),
609    case Global of
610        false ->
611            recv_local_call(Local, [global_call]);
612        true ->
613            ?CT(?MODULE, exported_wrap, [global_call])
614    end.
615
616local_call(Local) ->
617    lambda_slave(fun() -> exported_wrap(local_call) end),
618    recv_local_call(Local, [local_call]).
619
620recv_local_call(Local, Args) ->
621    case lists:member(local, Local) of
622        false ->
623            ok;
624        true ->
625            ?CT(?MODULE, exported_wrap, Args)
626    end,
627    case lists:member(meta, Local) of
628        false ->
629            ok;
630        true ->
631            ?CTT(?MODULE, exported_wrap, Args)
632    end,
633    ok.
634
635combinations([_]=One) ->
636    [One];
637combinations([H|T]) ->
638    Cs = combinations(T),
639    [[H|C] || C <- Cs] ++ Cs.
640
641stack_grow_test() ->
642    setup([call,return_to]),
643    1 = erlang:trace_pattern({?MODULE,loop,4},
644                             [{'_',[],[{return_trace}]}],[local]),
645    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
646    Num = 1 bsl 15,
647    Fun =
648    fun(_F,0) -> ok;
649       (F,N) ->
650            receive _A ->
651                        receive _B ->
652                                    receive _C ->
653                                                F(F,N-1)
654                                    end
655                        end
656            end
657    end,
658    apply_slave_async(?MODULE,loop,[{hej,hopp},[a,b,c],4.5,Num]),
659    Fun(Fun,Num + 1),
660    ?NM,
661    ok.
662
663
664info_test() ->
665    Flags1 = lists:sort([call,return_to]),
666    Pid = setup(Flags1),
667    Prog = [{['$1'],[{is_integer,'$1'}],[{message, false}]},
668            {'_',[],[]}],
669    erlang:trace_pattern({?MODULE,exported_wrap,1},Prog,[local]),
670    erlang:trace_pattern({?MODULE,slave,'_'},false,[local]),
671    Self = self(),
672    {flags,L} = erlang:trace_info(Pid,flags),
673    case lists:sort(L) of
674        Flags1 ->
675            ok;
676        Wrong1 ->
677            exit({bad_result, {erlang,trace_info,[Pid,flags]},
678                  {expected, Flags1}, {got, Wrong1}})
679    end,
680    {tracer,Tracer} = erlang:trace_info(Pid,tracer),
681    case Tracer of
682        Self ->
683            ok;
684        Wrong2 ->
685            exit({bad_result, {erlang,trace_info,[Pid,tracer]},
686                  {expected, Self}, {got, Wrong2}})
687    end,
688    {traced,local} = erlang:trace_info({?MODULE,exported_wrap,1},traced),
689    {match_spec, MS} =
690    erlang:trace_info({?MODULE,exported_wrap,1},match_spec),
691    case MS of
692        Prog ->
693            ok;
694        Wrong3 ->
695            exit({bad_result, {erlang,trace_info,
696                               [{?MODULE,exported_wrap,1},
697                                match_spec]},
698                  {expected, Prog}, {got, Wrong3}})
699    end,
700    erlang:garbage_collect(self()),
701    receive
702    after 1 ->
703              ok
704    end,
705    io:format("~p~n",[MS]),
706    {match_spec,MS2} =
707    erlang:trace_info({?MODULE,exported_wrap,1},match_spec),
708    io:format("~p~n",[MS2]),
709    erlang:trace_pattern({?MODULE,exported_wrap,1},[],[]),
710    {traced,global} =
711    erlang:trace_info({?MODULE,exported_wrap,1},traced),
712    {match_spec,[]} =
713    erlang:trace_info({?MODULE,exported_wrap,1},match_spec),
714    {traced,undefined} =
715    erlang:trace_info({?MODULE,exported_wrap,2},traced),
716    {match_spec,undefined} =
717    erlang:trace_info({?MODULE,exported_wrap,2},match_spec),
718    {traced,false} = erlang:trace_info({?MODULE,exported,1},traced),
719    {match_spec,false} =
720    erlang:trace_info({?MODULE,exported,1},match_spec),
721    shutdown(),
722    ok.
723
724delete_test(Config) ->
725    Priv = proplists:get_value(priv_dir, Config),
726    Data = proplists:get_value(data_dir, Config),
727    File = filename:join(Data, "trace_local_dummy"),
728    {ok,trace_local_dummy} = c:c(File, [{outdir,Priv}]),
729    code:purge(trace_local_dummy),
730    code:delete(trace_local_dummy),
731    0 = erlang:trace_pattern({trace_local_dummy,'_','_'},true,[local]),
732    ?NM,
733    ok.
734
735
736
737%%% exception_test %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738
739exception_test(Opts) ->
740    {ProcFlags,PatFlags} =
741    case proplists:get_bool(meta, Opts) of
742        true  -> {[timestamp],[meta]};
743        false -> {[call,return_to,timestamp],[local]}
744    end,
745    case proplists:get_bool(nocatch, Opts) of
746        false ->
747            Exceptions = exceptions(),
748            exception_test_setup(ProcFlags, PatFlags),
749            lists:foreach(
750              fun ({Func,Args}) ->
751                      exception_test(Opts, Func, Args)
752              end,
753              Exceptions),
754            shutdown();
755        true ->
756            Exceptions = exceptions(),
757            lists:foreach(
758              fun ({Func,Args}) ->
759                      exception_test_setup(
760                        [procs|ProcFlags],
761                        PatFlags),
762                      exception_test(Opts, Func, Args),
763                      shutdown()
764              end,
765              Exceptions)
766    end,
767    ok.
768
769exceptions() ->
770    Ref = make_ref(),
771    N   = 200000,
772    LiL = seq(1, N-1, N),	% Long Improper List
773    LL  = seq(1, N, []),  	% Long List
774    [{{erlang,exit},  [done]},
775     {{erlang,error}, [1.0]},
776     {{erlang,error}, [Ref,[]]},
777     {{erlang,throw}, [4711]},
778     {{erlang,'++'},    [[17],seventeen]},
779     {{erlang,'++'},    [Ref,[125.125]]},
780     {{?MODULE,match},  [ref,Ref]},
781     {{?MODULE,match},  [Ref,Ref]},
782     {{?MODULE,clause}, [ref,Ref]},
783     {{?MODULE,clause}, [Ref,Ref]},
784     {{?MODULE,id},     [4711.0]},
785     {{?MODULE,undef},  [[Ref|Ref]]},
786     {{?MODULE,lists_reverse}, [LiL,[]]},
787     {{?MODULE,lists_reverse}, [LL,[]]}].
788
789exception_test_setup(ProcFlags, PatFlags) ->
790    Pid = setup(ProcFlags),
791    io:format("=== exception_test_setup(~p, ~p): ~p~n",
792              [ProcFlags,PatFlags,Pid]),
793    Mprog = [{'_',[],[{exception_trace}]}],
794    erlang:trace_pattern({?MODULE,'_','_'}, Mprog, PatFlags),
795    erlang:trace_pattern({?MODULE,slave,'_'},false,PatFlags),
796    [1,1,1,1,1] =
797    [erlang:trace_pattern({erlang,F,A}, Mprog, PatFlags)
798     || {F,A} <- [{exit,1},{error,1},{error,2},{throw,1},{'++',2}]],
799    1 = erlang:trace_pattern({lists,reverse,2}, Mprog, PatFlags),
800    ok.
801
802-record(exc_opts, {nocatch=false, meta=false}).
803
804exception_test(Opts, Func0, Args0) ->
805    io:format("=== exception_test(~p, ~p, ~p)~n",
806              [Opts,Func0,abbr(Args0)]),
807    Apply = proplists:get_bool(apply, Opts),
808    Function = proplists:get_bool(function, Opts),
809    Nocatch = proplists:get_bool(nocatch, Opts),
810    Meta = proplists:get_bool(meta, Opts),
811    ExcOpts = #exc_opts{nocatch=Nocatch,meta=Meta},
812
813    %% Func0 and Args0 are for the innermost call, now we will
814    %% wrap them in wrappers...
815    {Func1,Args1} =
816    case Function of
817        true  -> {fun exc/2,[Func0,Args0]};
818        false -> {Func0,Args0}
819    end,
820
821    {Func,Args} =
822    case Apply of
823        true  -> {{erlang,apply},[Func1,Args1]};
824        false -> {Func1,Args1}
825    end,
826
827    R1 = exc_slave(ExcOpts, Func, Args),
828    Stack2 = [{?MODULE,exc_top,3,[]},{?MODULE,slave,2,[]}],
829    Stack3 = [{?MODULE,exc,2,[]}|Stack2],
830    Rs =
831    case x_exc_top(ExcOpts, Func, Args) of % Emulation
832        {crash,{Reason,Stack}}=R when is_list(Stack) ->
833            [R,
834             {crash,{Reason,Stack++Stack2}},
835             {crash,{Reason,Stack++Stack3}}];
836        R ->
837            [R]
838    end,
839    exception_validate(R1, Rs),
840    case R1 of
841        {crash,Crash} ->
842            expect({trace_ts,exit,Crash});
843        _ when not Meta ->
844            expect({rtt,{?MODULE,slave,2}});
845        _ ->
846            ok
847    end,
848    expect({nm}).
849
850exception_validate(R0, Rs0) ->
851    R = clean_location(R0),
852    Rs = [clean_location(E) || E <- Rs0],
853    exception_validate_1(R, Rs).
854
855exception_validate_1(R1, [R2|Rs]) ->
856    case [R1|R2] of
857        [R|R] ->
858            ok;
859        [{crash,{badarg,[{lists,reverse,[L1a,L1b],_}|T]}}|
860         {crash,{badarg,[{lists,reverse,[L2a,L2b],_}|T]}}] ->
861            same({crash,{badarg,[{lists,reverse,
862                                  [lists:reverse(L1b, L1a),[]],[]}|T]}},
863                 {crash,{badarg,[{lists,reverse,
864                                  [lists:reverse(L2b, L2a),[]],[]}|T]}});
865        _ when is_list(Rs), Rs =/= [] ->
866            exception_validate(R1, Rs)
867    end.
868
869clean_location({crash,{Reason,Stk0}}) ->
870    Stk = [{M,F,A,[]} || {M,F,A,_} <- Stk0],
871    {crash,{Reason,Stk}};
872clean_location(Term) -> Term.
873
874concurrency(_Config) ->
875    N = erlang:system_info(schedulers),
876
877    %% Spawn 2*N processes that spin in a tight infinite loop,
878    %% and one process that will turn on and off local call
879    %% trace on the infinite_loop/0 function. We expect the
880    %% emulator to crash if there is a memory barrier bug or
881    %% if an aligned word-sized write is not atomic.
882
883    Ps0 = [spawn_monitor(fun() -> infinite_loop() end) ||
884           _ <- lists:seq(1, 2*N)],
885    OnAndOff = fun() -> concurrency_on_and_off() end,
886    Ps1 = [spawn_monitor(OnAndOff)|Ps0],
887    timer:sleep(1000),
888
889    %% Now spawn off N more processes that turn on off and off
890    %% a local trace pattern.
891    Ps = [spawn_monitor(OnAndOff) || _ <- lists:seq(1, N)] ++ Ps1,
892    timer:sleep(1000),
893
894    %% Clean up.
895    [exit(Pid, kill) || {Pid,_} <- Ps],
896    [receive
897         {'DOWN',Ref,process,Pid,killed} -> ok
898     end || {Pid,Ref} <- Ps],
899    erlang:trace_pattern({?MODULE,infinite_loop,0}, false, [local]),
900    ok.
901
902concurrency_on_and_off() ->
903    1 = erlang:trace_pattern({?MODULE,infinite_loop,0}, true, [local]),
904    1 = erlang:trace_pattern({?MODULE,infinite_loop,0}, false, [local]),
905    concurrency_on_and_off().
906
907infinite_loop() ->
908    infinite_loop().
909
910%%% Tracee target functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911%%%
912
913loop(D1,D2,D3,0) ->
914    io:format("~p~n",[[D1,D2,D3]]),
915    0;
916loop(D1,D2,D3,N) ->
917    max(N,loop(D1,D2,D3,N-1)).
918
919exported_wrap(Val) ->
920    exported(Val).
921
922exported(Val) ->
923    [Val | local(Val)]. %% Non tail recursive local call
924
925local(Val) ->
926    [Val | local2(Val)]. %% Non tail recursive local call
927
928local2(Val) ->
929    local_tail(Val). %% Tail recursive call
930
931local_tail(Val) ->
932    [Val , erlang:phash2(1,1023)].
933
934
935
936%%% exc_slave/3 tracee target functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
937%%%
938
939exc_top(ExcOpts, Func, Args) ->
940    case ExcOpts#exc_opts.nocatch of
941        false ->
942            try exc_jump(Func, Args) of
943                Value ->
944                    {value,Value}
945            catch
946                Class:Reason ->
947                    {Class,Reason}
948            end;
949        true ->
950            {value,exc_jump(Func, Args)}
951    end.
952
953%% x_* functions emulate the non-x_* ones.
954%% x_* functions below x_exc_top
955%% return {value,Value} or {Class,Reason}.
956%% The only possible place for exception
957%% is below exc/2.
958x_exc_top(ExcOpts, Func, Args) ->
959    Rtt = not ExcOpts#exc_opts.meta,
960    expect({ctt,{?MODULE,exc_top},[ExcOpts,Func,Args]}),
961    case x_exc_jump(ExcOpts, Func, Args) of
962        Result when not ExcOpts#exc_opts.nocatch ->
963            expect([Rtt,{rtt,{?MODULE,exc_top,3}},
964                    ?LINE,{rft,{?MODULE,exc_top,3},Result}]),
965            Result;
966        {value,_}=Result ->
967
968            expect([Rtt,{rtt,{?MODULE,exc_top,3}},
969                    ?LINE,{rft,{?MODULE,exc_top,3},Result}]),
970            Result;
971        {exit,Reason}=CR ->
972            expect({eft,{?MODULE,exc_top,3},CR}),
973            {crash,Reason};
974        {error,Reason}=CR ->
975            expect({eft,{?MODULE,exc_top,3},CR}),
976            {crash,{Reason,x_exc_stacktrace()}};
977        CR ->
978            expect({eft,{?MODULE,exc_top,3},CR}),
979            {crash,CR}
980    end.
981
982exc_jump(Func, Args) ->
983    exc(Func, Args, jump).
984
985x_exc_jump(ExcOpts, Func, Args) ->
986    expect({ctt,{?MODULE,exc_jump},[Func,Args]}),
987    case x_exc(ExcOpts, Func, Args, jump) of
988        {value,Value}=Result ->
989            expect({rft,{?MODULE,exc_jump,2},Value}),
990            Result;
991        CR ->
992            expect({eft,{?MODULE,exc_jump,2},CR}),
993            CR
994    end.
995
996exc(Func, Args, jump) ->
997    exc(Func, Args, do);
998exc(Func, Args, do) ->
999    exc(Func, Args).
1000
1001x_exc(ExcOpts, Func, Args, jump) ->
1002    expect({ctt,{?MODULE,exc},[Func,Args,jump]}),
1003    case x_exc(ExcOpts, Func, Args, do) of
1004        {value,Value}=Result ->
1005            expect({rft,{?MODULE,exc,3},Value}),
1006            Result;
1007        CR ->
1008            expect({eft,{?MODULE,exc,3},CR}),
1009            CR
1010    end;
1011x_exc(ExcOpts, Func, Args, do) ->
1012    expect({ctt,{?MODULE,exc},[Func,Args,do]}),
1013    case x_exc(ExcOpts, Func, Args) of
1014        {value,Value}=Result ->
1015            expect({rft,{?MODULE,exc,3},Value}),
1016            Result;
1017        CR ->
1018            expect({eft,{?MODULE,exc,3},CR}),
1019            CR
1020    end.
1021
1022exc({erlang,apply}, [{M,F},A]) ->
1023    erlang:apply(M, F, id(A));
1024exc({erlang,apply}, [F,A]) ->
1025    erlang:apply(F, id(A));
1026exc({erlang,error}, [E]) ->
1027    erlang:error(id(E));
1028exc({erlang,error}, [E,S]) ->
1029    erlang:error(E, id(S));
1030exc({erlang,exit}, [E]) ->
1031    erlang:exit(id(E));
1032exc({erlang,throw}, [E]) ->
1033    erlang:throw(id(E));
1034exc({erlang,'++'}, [A,B]) ->
1035    erlang:'++'(A, id(B));
1036exc({?MODULE,match}, [A,B]) ->
1037    match(A, id(B));
1038exc({?MODULE,clause}, [A,B]) ->
1039    clause(A, id(B));
1040exc({?MODULE,id}, [E]) ->
1041    id(id(E));
1042exc({?MODULE,undef}, [E]) ->
1043    undef(id(E));
1044exc({?MODULE,lists_reverse}, [A,B]) ->
1045    lists_reverse(A, id(B));
1046exc(Func, [A,B]) when is_function(Func, 2) ->
1047    Func(A, id(B)).
1048
1049x_exc(ExcOpts, {erlang,apply}=Func0, [{_,_}=Func,Args]=Args0) ->
1050    expect({ctt,{?MODULE,exc},[Func0,Args0]}),
1051    x_exc_body(ExcOpts, Func, Args, true);
1052x_exc(ExcOpts, {erlang,apply}=Func0, [Func,Args]=Args0)
1053  when is_function(Func, 2)->
1054    expect({ctt,{?MODULE,exc},[Func0,Args0]}),
1055    x_exc_func(ExcOpts, Func, Args, Args);
1056x_exc(ExcOpts, {_,_}=Func, Args) ->
1057    expect({ctt,{?MODULE,exc},[Func,Args]}),
1058    x_exc_body(ExcOpts, Func, Args, false);
1059x_exc(ExcOpts, Func0, [_,Args]=Args0)
1060  when is_function(Func0, 2) ->
1061    expect({ctt,{?MODULE,exc},[Func0,Args0]}),
1062    x_exc_func(ExcOpts, Func0, Args0, Args).
1063
1064x_exc_func(ExcOpts, Func, [Func1,Args1]=Args, Id) ->
1065    %% Assumes the called fun =:= fun exc/2,
1066    %% will utterly fail otherwise.
1067    Rtt = not ExcOpts#exc_opts.meta,
1068    {module,M} = erlang:fun_info(Func, module),
1069    {name,F} = erlang:fun_info(Func, name),
1070    expect([{ctt,{?MODULE,id},[Id]},
1071            ?LINE,{rft,{?MODULE,id,1},Id},
1072            ?LINE,Rtt,{rtt,{?MODULE,exc,2}},
1073            ?LINE,{ctt,{M,F},Args}]),
1074    case x_exc(ExcOpts, Func1, Args1) of
1075        {value,Value}=Result ->
1076            expect([{rft,{M,F,2},Value},
1077                    ?LINE,{rft,{?MODULE,exc,2},Value}]),
1078            Result;
1079        CR ->
1080            expect([{eft,{M,F,2},CR},
1081                    ?LINE,{eft,{?MODULE,exc,2},CR}]),
1082            CR
1083    end.
1084
1085x_exc_body(ExcOpts, {M,F}=Func, Args, Apply) ->
1086    Nocatch = ExcOpts#exc_opts.nocatch,
1087    Rtt = not ExcOpts#exc_opts.meta,
1088    Id = case Apply of
1089             true  -> Args;
1090             false -> lists:last(Args)
1091         end,
1092    expect([{ctt,{?MODULE,id},[Id]},
1093            ?LINE,{rft,{?MODULE,id,1},Id},
1094            ?LINE,Rtt,{rtt,{?MODULE,exc,2}},
1095            ?LINE,{ctt,{M,F},Args}]),
1096    Arity = length(Args),
1097    try exc(Func, Args) of
1098        Value ->
1099            x_exc_value(Rtt, M, F, Args, Arity, Value),
1100            case expect() of
1101                {rtt,{M,F,Arity}} when Rtt, Apply ->
1102                    %% We may get the above when
1103                    %% applying a BIF.
1104                    expect({rft,{?MODULE,exc,2},Value});
1105                {rtt,{?MODULE,exc,2}} when Rtt, not Apply ->
1106                    %% We may get the above when
1107                    %% calling a BIF.
1108                    expect({rft,{?MODULE,exc,2},Value});
1109                {rft,{?MODULE,exc,2},Value} ->
1110                    ok
1111            end,
1112            {value,Value}
1113    catch
1114        Thrown when Nocatch ->
1115            CR = {error,{nocatch,Thrown}},
1116            x_exc_exception(Rtt, M, F, Args, Arity, CR),
1117            expect({eft,{?MODULE,exc,2},CR}),
1118            CR;
1119        Class:Reason ->
1120            CR = {Class,Reason},
1121            x_exc_exception(Rtt, M, F, Args, Arity, CR),
1122            expect({eft,{?MODULE,exc,2},CR}),
1123            CR
1124    end.
1125
1126x_exc_value(Rtt, ?MODULE, lists_reverse, [La,Lb], 2, R) ->
1127    L = lists:reverse(Lb, La),
1128    expect([fun ({ctt,{lists,reverse},[L1,L2]}) ->
1129                    same(L, lists:reverse(L2, L1)),
1130                    next;
1131                (Msg) ->
1132                    same({rft,{lists,reverse,2},R}, Msg),
1133                    same(R, lists:reverse(L, [])),
1134                    done
1135            end,
1136            ?LINE,Rtt,{rtt,{?MODULE,lists_reverse,2}},
1137            ?LINE,{rft,{?MODULE,lists_reverse,2},R}]);
1138x_exc_value(_Rtt, M, F, _, Arity, Value) ->
1139    expect({rft,{M,F,Arity},Value}).
1140
1141x_exc_exception(_Rtt, ?MODULE, lists_reverse, [La,Lb], 2, CR) ->
1142    L = lists:reverse(Lb, La),
1143    expect([fun ({ctt,{lists,reverse},[L1,L2]}) ->
1144                    same(L, lists:reverse(L2, L1)),
1145                    next;
1146                (Msg) ->
1147                    same({eft,{lists,reverse,2},CR}, Msg),
1148                    done
1149            end,
1150            ?LINE,{eft,{?MODULE,lists_reverse,2},CR}]);
1151x_exc_exception(Rtt, ?MODULE, undef, [_], 1, {Class,Reason}=CR) ->
1152    expect([{ctt,{erlang,Class},[Reason]},
1153            ?LINE,{eft,{erlang,Class,1},CR},
1154            ?LINE,Rtt,{rtt,{error_handler,crash,1}},
1155            ?LINE,{eft,{?MODULE,undef,1},CR}]);
1156x_exc_exception(_Rtt, M, F, _, Arity, CR) ->
1157    expect({eft,{M,F,Arity},CR}).
1158
1159x_exc_stacktrace() ->
1160    x_exc_stacktrace(erlang:get_stacktrace()).
1161%% Truncate stacktrace to below exc/2
1162x_exc_stacktrace([{?MODULE,x_exc,4,_}|_]) -> [];
1163x_exc_stacktrace([{?MODULE,x_exc_func,4,_}|_]) -> [];
1164x_exc_stacktrace([{?MODULE,x_exc_body,4,_}|_]) -> [];
1165x_exc_stacktrace([{?MODULE,exc,2,_}|_]) -> [];
1166x_exc_stacktrace([H|T]) ->
1167    [H|x_exc_stacktrace(T)].
1168
1169
1170
1171match(A, B) ->
1172    A = B.
1173
1174clause(A, A) ->
1175    A.
1176
1177id(Id) ->
1178    Id.
1179
1180undef(X) ->
1181    ?MODULE:undef(X, X). % undef
1182
1183lists_reverse(A, B) ->
1184    lists:reverse(A, B).
1185
1186
1187
1188%%% Tracee (slave) handling %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189%%%
1190
1191slave(Dest, Sync) ->
1192    Dest ! Sync,
1193    receive
1194        {From,Tag,{apply,M,F,A}} when is_pid(From) ->
1195            ?dbgformat("Apply: ~p:~p/~p (~p)~n",[M,F,length(A),A]),
1196            Res = apply(M,F,A),
1197            ?dbgformat("done Apply: ~p:~p/~p (~p)~n",[M,F,length(A),A]),
1198            From ! {Tag,Res},
1199            slave(From, Tag);
1200        {From,Tag,{lambda,Fun}} when is_pid(From) ->
1201            Res = Fun(),
1202            From ! {Tag,Res},
1203            slave(From, Tag);
1204        {From,Tag,{exc_top,Catch,Func,Args}} when is_pid(From) ->
1205            ?dbgformat("Exc: ~p ~p~p ~n",[Catch,Func,Args]),
1206            Res = exc_top(Catch, Func, Args),
1207            ?dbgformat("done Exc: ~p ~p~p ~n",[Catch,Func,Args]),
1208            From ! {Tag,Res},
1209            slave(From,Tag);
1210        die ->
1211            exit(normal)
1212    end.
1213
1214setup(ProcFlags) ->
1215    trace_off(),
1216    flush(100),
1217    Self = self(),
1218    Sync = make_ref(),
1219    Pid = spawn(fun () -> slave(Self, Sync) end),
1220    Mref = erlang:monitor(process, Pid),
1221    receive
1222        Sync ->
1223            put(slave, {Pid,Mref}),
1224            case ProcFlags of
1225                [] -> ok;
1226                _ ->
1227                    erlang:trace(Pid, true, ProcFlags)
1228            end,
1229            Pid
1230    end.
1231
1232shutdown() ->
1233    trace_off(),
1234    case get(slave) of
1235        {Pid,Mref} ->
1236            try erlang:is_process_alive(Pid) of
1237                true ->
1238                    Pid ! die,
1239                    receive
1240                        {'DOWN',Mref,process,Pid,Reason} ->
1241                            Reason
1242                    end;
1243                _ ->
1244                    not_alive
1245            catch _:_ ->
1246                    undefined
1247            end;
1248        _ ->
1249            undefined
1250    end.
1251
1252trace_off() ->
1253    erlang:trace_pattern({'_','_','_'},false,[]),
1254    erlang:trace_pattern({'_','_','_'},false,[local]),
1255    erlang:trace_pattern({'_','_','_'},false,[meta]),
1256    erlang:trace(all, false, [all]).
1257
1258
1259apply_slave_async(M,F,A) ->
1260    {Pid,Mref} = get(slave),
1261    spawn(?MODULE,apply_slave_async,[M,F,A,Pid,Mref]),
1262    Pid.
1263
1264apply_slave_async(M,F,A,Pid,Mref) ->
1265    Tag = make_ref(),
1266    Pid ! {self(),Tag,{apply,M,F,A}},
1267    result(Tag, Mref).
1268
1269apply_slave(M,F,A) ->
1270    request({apply,M,F,A}).
1271
1272lambda_slave(Fun) ->
1273    request({lambda,Fun}).
1274
1275exc_slave(Opts, Func, Args) ->
1276    try request({exc_top,Opts,Func,Args})
1277    catch
1278        Reason ->
1279            {crash,Reason}
1280    end.
1281
1282request(Request) ->
1283    Tag = make_ref(),
1284    {Pid,Mref} = get(slave),
1285    Pid ! {self(),Tag,Request},
1286    result(Tag, Mref).
1287
1288result(Tag, Mref) ->
1289    receive
1290        {Tag,Result} ->
1291            receive
1292                Tag ->
1293                    Result
1294            end;
1295        {'DOWN',Mref,process,_Pid,Reason} ->
1296            throw(Reason)
1297    end.
1298
1299
1300
1301%%% Some receive helpers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302%%%
1303
1304receive_next() ->
1305    receive_next(?DEFAULT_RECEIVE_TIMEOUT).
1306
1307receive_next(TO) ->
1308    receive
1309        M ->
1310            M
1311    after TO ->
1312              ct:fail(timeout)
1313    end.
1314
1315receive_no_next(TO) ->
1316    receive M ->
1317                ct:fail({unexpected_message,[M|flush(TO)]})
1318    after TO ->
1319              ok
1320    end.
1321
1322flush(T) ->
1323    receive
1324        M ->
1325            [M|flush(T)]
1326    after T ->
1327              []
1328    end.
1329
1330
1331
1332%%% Helpers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333%%%
1334
1335%% Do not build garbage
1336%%
1337seq(M, N, R) when M =< N ->
1338    seq(M, N-1, [N|R]);
1339seq(_, _, R) -> R.
1340
1341%% Do not call traced lists:reverse
1342reverse(L) ->
1343    reverse(L, []).
1344%%
1345reverse([], R) -> R;
1346reverse([H|T], R) ->
1347    reverse(T, [H|R]).
1348
1349%% Abbreviate large complex terms to avoid croaking printout
1350%%
1351abbr(Term) ->
1352    abbr(Term, 20).
1353%%
1354abbr(Tuple, N) when is_tuple(Tuple) ->
1355    list_to_tuple(abbr_tuple(Tuple, N, 1));
1356abbr(List, N) when is_list(List) ->
1357    abbr_list(List, N, []);
1358abbr(Term, _) -> Term.
1359%%
1360abbr_tuple(Tuple, N, J) when J =< size(Tuple) ->
1361    if J > N; N =< 0 ->
1362           ['...'];
1363       true ->
1364           [abbr(element(J, Tuple), N-1)|abbr_tuple(Tuple, J+1, N)]
1365    end;
1366abbr_tuple(_, _, _) ->
1367    [].
1368%%
1369abbr_list(_, 0, R) ->
1370    case io_lib:printable_list(R) of
1371        true ->
1372            reverse(R, "...");
1373        false ->
1374            reverse(R, '...')
1375    end;
1376abbr_list([H|T], N, R) ->
1377    M = N-1,
1378    abbr_list(T, M, [abbr(H, M)|R]);
1379abbr_list(T, _, R) ->
1380    reverse(R, T).
1381