1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1999-2012. All Rights Reserved.
    5: %% 
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %% 
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %% 
   17: %% %CopyrightEnd%
   18: 
   19: %%% Purpose : Tests the new call_trace BIF.
   20: 
   21: -module(call_trace_SUITE).
   22: 
   23: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   24: 	 init_per_group/2,end_per_group/2,
   25: 	 init_per_testcase/2,end_per_testcase/2,
   26: 	 hipe/1,process_specs/1,basic/1,flags/1,errors/1,pam/1,change_pam/1,
   27: 	 return_trace/1,exception_trace/1,on_load/1,deep_exception/1,
   28: 	 upgrade/1,
   29: 	 exception_nocatch/1,bit_syntax/1]).
   30: 
   31: %% Helper functions.
   32: 
   33: -export([bar/0,foo/0,foo/1,foo/2,expect/1,worker_foo/1,pam_foo/2,nasty/0,
   34: 	 id/1,deep/3,deep_1/3,deep_2/2,deep_3/2,deep_4/1,deep_5/1,
   35: 	 bs_sum_a/2,bs_sum_b/2]).
   36: 
   37: %% Debug
   38: -export([abbr/1,abbr/2]).
   39: 
   40: 
   41: -include_lib("test_server/include/test_server.hrl").
   42: 
   43: -define(P, 20).
   44: 
   45: suite() -> [{ct_hooks,[ts_install_cth]}].
   46: 
   47: all() -> 
   48:     Common = [errors, on_load],
   49:     NotHipe = [process_specs, basic, flags, pam, change_pam,
   50: 	       upgrade,
   51: 	       return_trace, exception_trace, deep_exception,
   52: 	       exception_nocatch, bit_syntax],
   53:     Hipe = [hipe],
   54:     case test_server:is_native(call_trace_SUITE) of
   55: 	true -> Hipe ++ Common;
   56: 	false -> NotHipe ++ Common
   57:     end.
   58: 
   59: groups() -> 
   60:     [].
   61: 
   62: init_per_suite(Config) ->
   63:     Config.
   64: 
   65: end_per_suite(_Config) ->
   66:     ok.
   67: 
   68: init_per_group(_GroupName, Config) ->
   69:     Config.
   70: 
   71: end_per_group(_GroupName, Config) ->
   72:     Config.
   73: 
   74: 
   75: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
   76:     Dog = ?t:timetrap(?t:seconds(30)),
   77:     [{watchdog, Dog}|Config].
   78: 
   79: end_per_testcase(_Func, Config) ->
   80:     Dog = ?config(watchdog, Config),
   81:     ?t:timetrap_cancel(Dog),
   82: 
   83:     %% Reloading the module will clear all trace patterns, and
   84:     %% in a debug-compiled emulator run assertions of the counters
   85:     %% for the number of traced exported functions in this module.
   86: 
   87:     c:l(?MODULE).
   88: 
   89: hipe(Config) when is_list(Config) ->
   90:     ?line 0 = erlang:trace_pattern({?MODULE,worker_foo,1}, true),
   91:     ?line 0 = erlang:trace_pattern({?MODULE,worker_foo,1}, true, [local]),
   92:     ?line AllFuncs = erlang:trace_pattern({'_','_','_'}, true),
   93: 
   94:     %% Make sure that a traced, exported function can still be found.
   95:     ?line true = erlang:function_exported(error_handler, undefined_function, 3),
   96:     ?line AllFuncs = erlang:trace_pattern({'_','_','_'}, false),
   97:     ok.
   98: 
   99: process_specs(doc) ->
  100:     "Tests 'all', 'new', and 'existing' for specifying processes.";
  101: process_specs(suite) -> [];
  102: process_specs(Config) when is_list(Config) ->
  103:     ?line Tracer = start_tracer(),
  104:     ?line {flags,[call]} = trace_info(self(), flags),
  105:     ?line {tracer,Tracer} = trace_info(self(), tracer),
  106:     ?line trace_func({?MODULE,worker_foo,1}, []),
  107: 
  108:     %% Test the 'new' flag.
  109: 
  110:     ?line {Work1A,Work1B} = start_and_trace(new, [1,2,3], A1B={3,2,1}),
  111:     {flags,[]} = trace_info(Work1A, flags),
  112:     {tracer,[]} = trace_info(Work1A, tracer),
  113:     {tracer,Tracer} = trace_info(Work1B, tracer),
  114:     {flags,[call]} = trace_info(Work1B, flags),
  115:     ?line expect({trace,Work1B,call,{?MODULE,worker_foo,[A1B]}}),
  116:     ?line unlink(Work1B),
  117:     ?line Mref = erlang:monitor(process, Work1B),
  118:     ?line exit(Work1B, kill),
  119:     receive
  120: 	{'DOWN',Mref,_,_,_} -> ok
  121:     end,
  122:     ?line undefined = trace_info(Work1B, flags),
  123:     ?line {flags,[]} = trace_info(new, flags),
  124:     ?line {tracer,[]} = trace_info(new, tracer),
  125: 
  126:     %% Test the 'existing' flag.
  127:     ?line {Work2A,_Work2B} = start_and_trace(existing, A2A=[5,6,7], [7,6,5]),
  128:     ?line expect({trace,Work2A,call,{?MODULE,worker_foo,[A2A]}}),
  129: 
  130:     %% Test the 'all' flag.
  131:     ?line {Work3A,Work3B} = start_and_trace(all, A3A=[12,13], A3B=[13,12]),
  132:     ?line expect({trace,Work3A,call,{?MODULE,worker_foo,[A3A]}}),
  133:     ?line expect({trace,Work3B,call,{?MODULE,worker_foo,[A3B]}}),
  134:     
  135:     ok.
  136: 
  137: start_and_trace(Flag, A1, A2) ->
  138:     W1 = start_worker(),
  139:     trace_pid(Flag, true, [call]),
  140:     W2 = start_worker(),
  141:     call_worker(W1, A1),
  142:     call_worker(W2, A2),
  143:     case Flag of
  144: 	new ->
  145: 	    {flags,[call]} = trace_info(new, flags),
  146: 	    {tracer,_} = trace_info(new, tracer);
  147: 	_Other ->
  148: 	    ok
  149:     end,
  150:     trace_pid(Flag, false, [call]),
  151:     {W1,W2}.
  152: 
  153: start_worker() ->
  154:     ?line spawn(fun worker_loop/0).
  155: 
  156: call_worker(Pid, Arg) ->
  157:     Pid ! {self(),{call,Arg}},
  158:     receive
  159: 	{result,Res} -> Res
  160:     after 5000 ->
  161: 	    ?line ?t:fail(no_answer_from_worker)
  162:     end.
  163: 
  164: worker_loop() ->
  165:     receive
  166: 	{From,{call,Arg}} ->
  167: 	    From ! {result,?MODULE:worker_foo(Arg)},
  168: 	    worker_loop();
  169: 	Other ->
  170: 	    exit({unexpected_message,Other})
  171:     end.
  172: 
  173: worker_foo(_Arg) ->
  174:     ok.
  175: 
  176: %% Basic test of the call tracing (we trace one process).
  177: basic(_Config) ->
  178:     case test_server:is_native(lists) of
  179: 	true -> {skip,"lists is native"};
  180: 	false -> basic()
  181:     end.
  182: 
  183: basic() ->
  184:     ?line start_tracer(),
  185:     ?line trace_info(self(), flags),
  186:     ?line trace_info(self(), tracer),
  187:     ?line 0 = trace_func({?MODULE,no_such_function,0}, []),
  188:     ?line {traced,undefined} = 
  189: 	trace_info({?MODULE,no_such_function,0}, traced),
  190:     ?line {match_spec, undefined} = 
  191: 	trace_info({?MODULE,no_such_function,0}, match_spec),
  192: 
  193:     %% Trace some functions...
  194: 
  195:     ?line trace_func({lists,'_','_'}, []),
  196: 
  197:     %% Make sure that tracing the same functions more than once
  198:     %% does not cause any problems.
  199:     ?line 3 = trace_func({?MODULE,foo,'_'}, true),
  200:     ?line 3 = trace_func({?MODULE,foo,'_'}, true),
  201:     ?line 1 = trace_func({?MODULE,bar,0}, true),
  202:     ?line 1 = trace_func({?MODULE,bar,0}, true),
  203:     ?line {traced,global} = trace_info({?MODULE,bar,0}, traced),
  204:     ?line 1 = trace_func({erlang,list_to_integer,1}, true),
  205:     ?line {traced,global} = trace_info({erlang,list_to_integer,1}, traced),
  206: 
  207:     %% ... and call them...
  208: 
  209:     ?line AList = [x,y,z],
  210:     ?line true = lists:member(y, AList),
  211:     ?line foo0 = ?MODULE:foo(),
  212:     ?line 4 = ?MODULE:foo(3),
  213:     ?line 11 = ?MODULE:foo(7, 4),
  214:     ?line ok = ?MODULE:bar(),
  215:     ?line 42 = list_to_integer(non_literal("42")),
  216: 
  217:     %% ... make sure the we got trace messages (but not for ?MODULE:expect/1).
  218: 
  219:     ?line Self = self(),
  220:     ?line ?MODULE:expect({trace,Self,call,{lists,member,[y,AList]}}),
  221:     ?line ?MODULE:expect({trace,Self,call,{?MODULE,foo,[]}}),
  222:     ?line ?MODULE:expect({trace,Self,call,{?MODULE,foo,[3]}}),
  223:     ?line ?MODULE:expect({trace,Self,call,{?MODULE,foo,[7,4]}}),
  224:     ?line ?MODULE:expect({trace,Self,call,{?MODULE,bar,[]}}),
  225:     ?line ?MODULE:expect({trace,Self,call,{erlang,list_to_integer,["42"]}}),
  226: 
  227:     %% Turn off trace for this module and call functions...
  228: 
  229:     ?line trace_func({?MODULE,'_','_'}, false),
  230:     ?line {traced,false} = trace_info({?MODULE,bar,0}, traced),
  231:     ?line foo0 = ?MODULE:foo(),
  232:     ?line 4 = ?MODULE:foo(3),
  233:     ?line 11 = ?MODULE:foo(7, 4),
  234:     ?line ok = ?MODULE:bar(),
  235:     ?line [1,2,3,4,5,6,7,8,9,10] = lists:seq(1, 10),
  236:     ?line 777 = list_to_integer(non_literal("777")),
  237: 
  238:     %% ... turn on all trace messages...
  239: 
  240:     ?line trace_func({'_','_','_'}, false),
  241:     ?line [b,a] = lists:reverse([a,b]),
  242: 
  243:     %% Read out the remaing trace messages.
  244: 
  245:     ?line ?MODULE:expect({trace,Self,call,{lists,seq,[1,10]}}),
  246:     ?line ?MODULE:expect({trace,Self,call,{erlang,list_to_integer,["777"]}}),
  247:     receive
  248: 	Any ->
  249: 	    ?line ?t:fail({unexpected_message,Any})
  250:     after 1 ->
  251: 	    ok
  252:     end,
  253: 
  254:     %% Turn on and then off tracing on all external functions.
  255:     %% This might cause the emulator to crasch later if it doesn't
  256:     %% restore all export entries properly.
  257: 
  258:     ?line AllFuncs = trace_func({'_','_','_'}, true),
  259:     io:format("AllFuncs = ~p", [AllFuncs]),
  260:     %% Make sure that a traced, exported function can still be found.
  261:     ?line true = erlang:function_exported(error_handler, undefined_function, 3),
  262:     ?line AllFuncs = trace_func({'_','_','_'}, false),
  263:     ?line erlang:trace_delivered(all),
  264:     receive
  265: 	{trace_delivered,_,_} -> ok
  266:     end,
  267:     c:flush(),					% Print the traces messages.
  268:     c:flush(),					% Print the traces messages.
  269: 
  270:     ?line {traced,false} = trace_info({erlang,list_to_integer,1}, traced),
  271: 
  272:     ok.
  273: 
  274: non_literal(X) -> X.
  275: 
  276: bar() ->
  277:     ok.
  278: 
  279: foo() -> foo0.
  280: foo(X) -> X+1.
  281: foo(X, Y) -> X+Y.
  282: 
  283: 
  284: %% Note that the semantics that this test case verifies
  285: %% are not explicitly specified in the docs (what I could find in R15B).
  286: %% This test case was written to verify that we do not change
  287: %% any behaviour with the introduction of "block-free" upgrade in R16.
  288: %% In short: Do not refer to this test case as an authority of how it must work.
  289: upgrade(doc) ->
  290:     "Test tracing on module being upgraded";
  291: upgrade(Config) when is_list(Config) ->
  292:     V1 = compile_version(my_upgrade_test, 1, Config),
  293:     V2 = compile_version(my_upgrade_test, 2, Config),
  294:     start_tracer(),
  295:     upgrade_do(V1, V2, false),
  296:     upgrade_do(V1, V2, true).
  297: 
  298: upgrade_do(V1, V2, TraceLocalVersion) ->
  299:     {module,my_upgrade_test} = erlang:load_module(my_upgrade_test, V1),
  300: 
  301: 
  302:     %% Test that trace is cleared after load_module
  303: 
  304:     trace_func({my_upgrade_test,'_','_'}, [], [global]),
  305:     case TraceLocalVersion of
  306: 	true -> trace_func({my_upgrade_test,local_version,0}, [], [local]);
  307: 	_ -> ok
  308:     end,
  309:     1 = my_upgrade_test:version(),
  310:     1 = my_upgrade_test:do_local(),
  311:     1 = my_upgrade_test:do_real_local(),
  312:     put('F1_exp', my_upgrade_test:make_fun_exp()),
  313:     put('F1_loc', my_upgrade_test:make_fun_local()),
  314:     1 = (get('F1_exp'))(),
  315:     1 = (get('F1_loc'))(),
  316: 
  317:     Self = self(),
  318:     expect({trace,Self,call,{my_upgrade_test,version,[]}}),
  319:     expect({trace,Self,call,{my_upgrade_test,do_local,[]}}),
  320:     expect({trace,Self,call,{my_upgrade_test,do_real_local,[]}}),
  321:     case TraceLocalVersion of
  322: 	true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}});
  323: 	_ -> ok
  324:     end,
  325:     expect({trace,Self,call,{my_upgrade_test,make_fun_exp,[]}}),
  326:     expect({trace,Self,call,{my_upgrade_test,make_fun_local,[]}}),
  327:     expect({trace,Self,call,{my_upgrade_test,version,[]}}), % F1_exp
  328:     case TraceLocalVersion of
  329: 	true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); % F1_loc
  330: 	_ -> ok
  331:     end,
  332: 
  333:     {module,my_upgrade_test} = erlang:load_module(my_upgrade_test, V2),
  334:     2 = my_upgrade_test:version(),
  335:     put('F2_exp', my_upgrade_test:make_fun_exp()),
  336:     put('F2_loc', my_upgrade_test:make_fun_local()),
  337:     2 = (get('F1_exp'))(),
  338:     1 = (get('F1_loc'))(),
  339:     2 = (get('F2_exp'))(),
  340:     2 = (get('F2_loc'))(),
  341:     expect(),
  342: 
  343:     put('F1_exp', undefined),
  344:     put('F1_loc', undefined),
  345:     erlang:garbage_collect(),
  346:     erlang:purge_module(my_upgrade_test),
  347: 
  348:     % Test that trace is cleared after delete_module
  349: 
  350:     trace_func({my_upgrade_test,'_','_'}, [], [global]),
  351:     case TraceLocalVersion of
  352: 	true -> trace_func({my_upgrade_test,local_version,0}, [], [local]);
  353: 	_ -> ok
  354:     end,
  355:     2 = my_upgrade_test:version(),
  356:     2 = my_upgrade_test:do_local(),
  357:     2 = my_upgrade_test:do_real_local(),
  358:     2 = (get('F2_exp'))(),
  359:     2 = (get('F2_loc'))(),
  360: 
  361:     expect({trace,Self,call,{my_upgrade_test,version,[]}}),
  362:     expect({trace,Self,call,{my_upgrade_test,do_local,[]}}),
  363:     expect({trace,Self,call,{my_upgrade_test,do_real_local,[]}}),
  364:     case TraceLocalVersion of
  365: 	true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}});
  366: 	_ -> ok
  367:     end,
  368:     expect({trace,Self,call,{my_upgrade_test,version,[]}}), % F2_exp
  369:     case TraceLocalVersion of
  370: 	true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); % F2_loc
  371: 	_ -> ok
  372:     end,
  373: 
  374:     true = erlang:delete_module(my_upgrade_test),
  375:     {'EXIT',{undef,_}} = (catch my_upgrade_test:version()),
  376:     {'EXIT',{undef,_}} = (catch ((get('F2_exp'))())),
  377:     2 = (get('F2_loc'))(),
  378:     expect(),
  379: 
  380:     put('F2_exp', undefined),
  381:     put('F2_loc', undefined),
  382:     erlang:garbage_collect(),
  383:     erlang:purge_module(my_upgrade_test),
  384:     ok.
  385: 
  386: compile_version(Module, Version, Config) ->
  387:     Data = ?config(data_dir, Config),
  388:     File = filename:join(Data, atom_to_list(Module)),
  389:     {ok,Module,Bin} = compile:file(File, [{d,'VERSION',Version},
  390: 					    binary,report]),
  391:     Bin.
  392: 
  393: 
  394: 
  395: %% Test flags (arity, timestamp) for call_trace/3.
  396: %% Also, test the '{tracer,Pid}' option.
  397: flags(_Config) ->
  398:     case test_server:is_native(filename) of
  399: 	true -> {skip,"filename is native"};
  400: 	false -> flags()
  401:     end.
  402: 
  403: flags() ->
  404:     ?line Tracer = start_tracer_loop(),
  405:     ?line trace_pid(self(), true, [call,{tracer,Tracer}]),
  406: 
  407:     %% Trace some functions...
  408: 
  409:     ?line trace_func({filename,'_','_'}, true),
  410: 
  411:     %% ... and call them...
  412: 
  413:     ?line Self = self(),
  414:     ?line filename:absname("nisse"),
  415:     ?line ?MODULE:expect({trace,Self,call,{filename,absname,["nisse"]}}),
  416:     ?line trace_pid(Self, true, [call,arity]),
  417:     ?line filename:absname("kalle"),
  418:     ?line filename:absname("kalle", "/root"),
  419:     ?line ?MODULE:expect({trace,Self,call,{filename,absname,1}}),
  420:     ?line ?MODULE:expect({trace,Self,call,{filename,absname,2}}),
  421:     ?line trace_info(Self, flags),
  422: 
  423:     %% Timestamp + arity.
  424: 
  425:     flag_test(fun() ->
  426: 		      ?line trace_pid(Self, true, [timestamp]),
  427: 		      ?line "dum" = filename:basename("/abcd/dum"),
  428: 		      ?line Ts = expect({trace_ts,Self,call,{filename,basename,1},ts}),
  429: 		      ?line trace_info(Self, flags),
  430: 		      Ts
  431: 	      end),
  432: 
  433:     %% Timestamp.
  434: 
  435:     ?line AnArg = "/abcd/hejsan",
  436:     flag_test(fun() ->
  437: 		      ?line trace_pid(Self, false, [arity]),
  438: 		      ?line "hejsan" = filename:basename(AnArg),
  439: 		      ?line Ts = expect({trace_ts,Self,call,
  440: 					 {filename,basename,[AnArg]},ts}),
  441: 		      ?line trace_info(Self, flags),
  442: 		      Ts
  443: 	      end),
  444: 
  445:     %% All flags turned off.
  446: 
  447:     ?line trace_pid(Self, false, [timestamp]),
  448:     ?line AnotherArg = filename:join(AnArg, "hoppsan"),
  449:     ?line "hoppsan" = filename:basename(AnotherArg),
  450:     ?line expect({trace,Self,call,{filename,join,[AnArg,"hoppsan"]}}),
  451:     ?line expect({trace,Self,call,{filename,basename,[AnotherArg]}}),
  452:     ?line trace_info(Self, flags),
  453:     
  454:     ok.
  455: 
  456: flag_test(Test) ->
  457:     Now = now(),
  458:     Ts = Test(),
  459:     case timer:now_diff(Ts, Now) of
  460: 	Time when Time < 5*1000000 ->
  461: 	    %% Reasonable short time.
  462: 	    ok;
  463: 	_Diff ->
  464: 	    %% Too large difference.
  465: 	    io:format("Now = ~p\n", [Now]),
  466: 	    io:format("Ts = ~p\n", [Ts]),
  467: 	    ?line ?t:fail()
  468:     end,
  469:     flag_test_cpu_timestamp(Test).
  470: 
  471: flag_test_cpu_timestamp(Test) ->
  472:     try erlang:trace(all, true, [cpu_timestamp]) of
  473: 	_ ->
  474: 	    io:format("CPU timestamps"),
  475: 	    Ts = Test(),
  476: 	    erlang:trace(all, false, [cpu_timestamp]),
  477: 	    Origin = {0,0,0},
  478: 	    Hour = 3600*1000000,
  479: 	    case timer:now_diff(Ts, Origin) of
  480: 		Diff when Diff < 4*Hour ->
  481: 		    %% In the worst case, CPU timestamps count from when this
  482: 		    %% Erlang emulator was started. The above test is a conservative
  483: 		    %% test that all CPU timestamps should pass.
  484: 		    ok;
  485: 		_Time ->
  486: 		    io:format("Strange CPU timestamp: ~p", [Ts]),
  487: 		    ?line ?t:fail()
  488: 	    end,
  489: 	    io:format("Turned off CPU timestamps")
  490:     catch
  491: 	error:badarg -> ok
  492:     end.
  493: 
  494: errors(doc) -> "Test bad arguments for trace/3 and trace_pattern/3.";
  495: errors(suite) -> [];
  496: errors(Config) when is_list(Config) ->
  497:     ?line expect_badarg_pid(aaa, true, []),
  498:     ?line expect_badarg_pid({pid,dum}, false, []),
  499:     ?line expect_badarg_func({'_','_',1}, []),
  500:     ?line expect_badarg_func({'_',gosh,1}, []),
  501:     ?line expect_badarg_func({xxx,'_',2}, []),
  502:     ?line expect_badarg_func({xxx,yyy,b}, glurp),
  503:     ok.
  504: 
  505: expect_badarg_pid(What, How, Flags) ->
  506:     case catch erlang:trace(What, How, Flags) of
  507: 	{'EXIT',{badarg,Where}} ->
  508: 	    io:format("trace(~p, ~p, ~p) ->\n  {'EXIT',{badarg,~p}}",
  509: 		      [What,How,Flags,Where]),
  510: 	    ok;
  511: 	Other ->
  512: 	    io:format("trace(~p, ~p, ~p) -> ~p",
  513: 		      [What,How,Flags,Other]),
  514: 	    ?t:fail({unexpected,Other})
  515:     end.
  516: 
  517: expect_badarg_func(MFA, Pattern) ->
  518:     case catch erlang:trace_pattern(MFA, Pattern) of
  519: 	{'EXIT',{badarg,Where}} ->
  520: 	    io:format("trace_pattern(~p, ~p) ->\n  {'EXIT',{badarg,~p}}",
  521: 		      [MFA,Pattern,Where]),
  522: 	    ok;
  523: 	Other ->
  524: 	    io:format("trace_pattern(~p, ~p) -> ~p",
  525: 		      [MFA, Pattern, Other]),
  526: 	    ?t:fail({unexpected,Other})
  527:     end.
  528: 
  529: pam(doc) -> "Basic test of PAM.";
  530: pam(suite) -> [];
  531: pam(Config) when is_list(Config) ->
  532:     ?line start_tracer(),
  533:     ?line Self = self(),
  534: 
  535:     %% Build the match program.
  536:     ?line Prog1 = {[{a,tuple},'$1'],[],[]},
  537:     ?line Prog2 = {[{a,bigger,tuple},'$1'],[],[{message,'$1'}]},
  538:     ?line MatchProg = [Prog1,Prog2],
  539:     ?line pam_trace(MatchProg),
  540: 
  541:     %% Do some calls.
  542:     ?line ?MODULE:pam_foo(not_a_tuple, [a,b]),
  543:     ?line ?MODULE:pam_foo({a,tuple}, [a,list]),
  544:     ?line ?MODULE:pam_foo([this,one,will,'not',match], dummy_arg),
  545:     ?line LongList = lists:seq(1,10),
  546:     ?line ?MODULE:pam_foo({a,bigger,tuple}, LongList),
  547: 
  548:     %% Check that we get the correct trace messages.
  549:     ?line expect({trace,Self,call,{?MODULE,pam_foo,[{a,tuple},[a,list]]}}),
  550:     ?line expect({trace,Self,call,
  551: 		  {?MODULE,pam_foo,[{a,bigger,tuple},LongList]},
  552: 		  LongList}),
  553: 
  554:     ?line trace_func({?MODULE,pam_foo,'_'}, false),
  555:     ok.
  556: 
  557: pam_trace(Prog) ->
  558:     1 = trace_func({?MODULE,pam_foo,'_'}, Prog),
  559:     {match_spec,Prog} = trace_info({?MODULE,pam_foo,2}, match_spec),
  560:     ok.
  561: 
  562: pam_foo(A, B) ->
  563:     {ok,A,B}.
  564: 
  565: 
  566: %% Test changing PAM programs for a function.
  567: change_pam(_Config) ->
  568:     case test_server:is_native(lists) of
  569: 	true -> {skip,"lists is native"};
  570: 	false -> change_pam()
  571:     end.
  572: 
  573: change_pam() ->
  574:     ?line start_tracer(),
  575:     ?line Self = self(),
  576: 
  577:     %% Install the first match program.
  578:     %% Test using timestamp at the same time.
  579: 
  580:     ?line trace_pid(Self, true, [call,arity,timestamp]),
  581:     ?line Prog1 = [{['$1','$2'],[],[{message,'$1'}]}],
  582:     ?line change_pam_trace(Prog1),
  583:     ?line [x,y] = lists:append(id([x]), id([y])),
  584:     ?line {heap_size,_} = erlang:process_info(Self, heap_size),
  585:     ?line expect({trace_ts,Self,call,{lists,append,2},[x],ts}),
  586:     ?line expect({trace_ts,Self,call,{erlang,process_info,2},Self,ts}),
  587: 
  588:     %% Install a new PAM program.
  589: 
  590:     ?line Prog2 = [{['$1','$2'],[],[{message,'$2'}]}],
  591:     ?line change_pam_trace(Prog2),
  592:     ?line [xx,yy] = lists:append(id([xx]), id([yy])),
  593:     ?line {current_function,_} = erlang:process_info(Self, current_function),
  594:     ?line expect({trace_ts,Self,call,{lists,append,2},[yy],ts}),
  595:     ?line expect({trace_ts,Self,call,{erlang,process_info,2},current_function,ts}),
  596: 
  597:     ?line 1 = trace_func({lists,append,2}, false),
  598:     ?line 1 = trace_func({erlang,process_info,2}, false),
  599:     ?line {match_spec,false} = trace_info({lists,append,2}, match_spec),
  600:     ?line {match_spec,false} = trace_info({erlang,process_info,2}, match_spec),
  601: 
  602:     ok.
  603: 
  604: change_pam_trace(Prog) ->
  605:     1 = trace_func({lists,append,2}, Prog),
  606:     1 = trace_func({erlang,process_info,2}, Prog),
  607:     {match_spec,Prog} = trace_info({lists,append,2}, match_spec),
  608:     {match_spec,Prog} = trace_info({erlang,process_info,2}, match_spec),
  609:     ok.
  610: 
  611: return_trace(_Config) ->
  612:     case test_server:is_native(lists) of
  613: 	true -> {skip,"lists is native"};
  614: 	false -> return_trace()
  615:     end.
  616: 
  617: return_trace() ->
  618:     X = {save,me},
  619:     ?line start_tracer(),
  620:     ?line Self = self(),
  621: 
  622:     %% Test call and return trace and timestamp.
  623: 
  624:     ?line trace_pid(Self, true, [call,timestamp]),
  625:     Stupid = {pointless,tuple},
  626:     ?line Prog1 = [{['$1','$2'],[],[{return_trace},{message,{Stupid}}]}],
  627:     ?line 1 = trace_func({lists,append,2}, Prog1),
  628:     ?line 1 = trace_func({erlang,process_info,2}, Prog1),
  629:     ?line {match_spec,Prog1} = trace_info({lists,append,2}, match_spec),
  630:     ?line {match_spec,Prog1} = trace_info({erlang,process_info,2}, match_spec),
  631: 
  632:     ?line [x,y] = lists:append(id([x]), id([y])),
  633:     Current = {current_function,{?MODULE,return_trace,0}},
  634:     ?line Current = erlang:process_info(Self, current_function),
  635:     ?line expect({trace_ts,Self,call,{lists,append,[[x],[y]]},Stupid,ts}),
  636:     ?line expect({trace_ts,Self,return_from,{lists,append,2},[x,y],ts}),
  637:     ?line expect({trace_ts,Self,call,{erlang,process_info,[Self,current_function]},
  638: 		  Stupid,ts}),
  639:     ?line expect({trace_ts,Self,return_from,{erlang,process_info,2},Current,ts}),
  640: 
  641:     %% Try catch/exit.
  642: 
  643:     ?line 1 = trace_func({?MODULE,nasty,0}, [{[],[],[{return_trace},{message,false}]}]),
  644:     ?line {'EXIT',good_bye} = (catch ?MODULE:nasty()),
  645:     ?line 1 = trace_func({?MODULE,nasty,0}, false),
  646: 
  647:     %% Turn off trace.
  648: 
  649:     ?line 1 = trace_func({lists,append,2}, false),
  650:     ?line 1 = trace_func({erlang,process_info,2}, false),
  651:     ?line {match_spec,false} = trace_info({lists,append,2}, match_spec),
  652:     ?line {match_spec,false} = trace_info({erlang,process_info,2}, match_spec),
  653: 
  654:     %% No timestamp, no trace message for call.
  655: 
  656:     ?line trace_pid(Self, false, [timestamp]),
  657:     ?line Prog2 = [{['$1','$2'],[],[{return_trace},{message,false}]},
  658: 		   {['$1'],[],[{return_trace},{message,false}]}],
  659:     ?line 1 = trace_func({lists,seq,2}, Prog2),
  660:     ?line 1 = trace_func({erlang,atom_to_list,1}, Prog2),
  661:     ?line {match_spec,Prog2} = trace_info({lists,seq,2}, match_spec),
  662:     ?line {match_spec,Prog2} = trace_info({erlang,atom_to_list,1}, match_spec),
  663: 
  664:     ?line lists:seq(2, 7),
  665:     ?line _ = atom_to_list(non_literal(nisse)),
  666:     ?line expect({trace,Self,return_from,{lists,seq,2},[2,3,4,5,6,7]}),
  667:     ?line expect({trace,Self,return_from,{erlang,atom_to_list,1},"nisse"}),
  668: 
  669:     %% Turn off trace.
  670: 
  671:     ?line 1 = trace_func({lists,seq,2}, false),
  672:     ?line 1 = trace_func({erlang,atom_to_list,1}, false),
  673:     ?line {match_spec,false} = trace_info({lists,seq,2}, match_spec),
  674:     ?line {match_spec,false} = trace_info({erlang,atom_to_list,1}, match_spec),
  675: 
  676:     ?line {save,me} = X,
  677:     
  678:     ok.
  679: 
  680: nasty() ->
  681:     exit(good_bye).
  682: 
  683: exception_trace(_Config) ->
  684:     case test_server:is_native(lists) of
  685: 	true -> {skip,"lists is native"};
  686: 	false -> exception_trace()
  687:     end.
  688: 
  689: exception_trace() ->
  690:     X = {save,me},
  691:     ?line start_tracer(),
  692:     ?line Self = self(),
  693: 
  694:     %% Test call and return trace and timestamp.
  695: 
  696:     ?line trace_pid(Self, true, [call,timestamp]),
  697:     Stupid = {pointless,tuple},
  698:     ?line Prog1 = [{['$1','$2'],[],[{exception_trace},{message,{Stupid}}]}],
  699:     ?line 1 = trace_func({lists,append,2}, Prog1),
  700:     ?line 1 = trace_func({erlang,process_info,2}, Prog1),
  701:     ?line {match_spec,Prog1} = trace_info({lists,append,2}, match_spec),
  702:     ?line {match_spec,Prog1} = 
  703: 	trace_info({erlang,process_info,2}, match_spec),
  704: 
  705:     ?line [x,y] = lists:append(id([x]), id([y])),
  706:     Current = {current_function,{?MODULE,exception_trace,0}},
  707:     ?line Current = erlang:process_info(Self, current_function),
  708:     ?line expect({trace_ts,Self,call,{lists,append,[[x],[y]]},Stupid,ts}),
  709:     ?line expect({trace_ts,Self,return_from,{lists,append,2},[x,y],ts}),
  710:     ?line expect({trace_ts,Self,call,{erlang,process_info,
  711: 				      [Self,current_function]},
  712: 		  Stupid,ts}),
  713:     ?line expect({trace_ts,Self,return_from,
  714: 		  {erlang,process_info,2},Current,ts}),
  715: 
  716:     %% Try catch/exit.
  717: 
  718:     ?line 1 = trace_func({?MODULE,nasty,0}, 
  719: 			 [{[],[],[{exception_trace},{message,false}]}]),
  720:     ?line {'EXIT',good_bye} = (catch ?MODULE:nasty()),
  721:     ?line expect({trace_ts,Self,exception_from,
  722: 		  {?MODULE,nasty,0},{exit,good_bye},ts}),
  723:     ?line 1 = trace_func({?MODULE,nasty,0}, false),
  724: 
  725:     %% Turn off trace.
  726: 
  727:     ?line 1 = trace_func({lists,append,2}, false),
  728:     ?line 1 = trace_func({erlang,process_info,2}, false),
  729:     ?line {match_spec,false} = trace_info({lists,append,2}, match_spec),
  730:     ?line {match_spec,false} = 
  731: 	trace_info({erlang,process_info,2}, match_spec),
  732: 
  733:     %% No timestamp, no trace message for call.
  734: 
  735:     ?line trace_pid(Self, false, [timestamp]),
  736:     ?line Prog2 = [{['$1','$2'],[],[{exception_trace},{message,false}]},
  737: 		   {['$1'],[],[{exception_trace},{message,false}]}],
  738:     ?line 1 = trace_func({lists,seq,2}, Prog2),
  739:     ?line 1 = trace_func({erlang,atom_to_list,1}, Prog2),
  740:     ?line {match_spec,Prog2} = trace_info({lists,seq,2}, match_spec),
  741:     ?line {match_spec,Prog2} = 
  742: 	trace_info({erlang,atom_to_list,1}, match_spec),
  743: 
  744:     ?line lists:seq(2, 7),
  745:     ?line _ = atom_to_list(non_literal(nisse)),
  746:     ?line expect({trace,Self,return_from,{lists,seq,2},[2,3,4,5,6,7]}),
  747:     ?line expect({trace,Self,return_from,{erlang,atom_to_list,1},"nisse"}),
  748: 
  749:     %% Turn off trace.
  750: 
  751:     ?line 1 = trace_func({lists,seq,2}, false),
  752:     ?line 1 = trace_func({erlang,atom_to_list,1}, false),
  753:     ?line {match_spec,false} = trace_info({lists,seq,2}, match_spec),
  754:     ?line {match_spec,false} = 
  755: 	trace_info({erlang,atom_to_list,1}, match_spec),
  756: 
  757:     ?line expect(),
  758:     ?line {save,me} = X,
  759:     ok.
  760: 
  761: on_load(doc) -> "Test the on_load argument for trace_pattern/3.";
  762: on_load(suite) -> [];
  763: on_load(Config) when is_list(Config) ->
  764:     ?line 0 = erlang:trace_pattern(on_load, []),
  765:     ?line {traced,global} = erlang:trace_info(on_load, traced),
  766:     ?line {match_spec,[]} = erlang:trace_info(on_load, match_spec),
  767: 
  768:     ?line 0 = erlang:trace_pattern(on_load, true, [local]),
  769:     ?line {traced,local} = erlang:trace_info(on_load, traced),
  770:     ?line {match_spec,[]} = erlang:trace_info(on_load, match_spec),
  771: 
  772:     ?line 0 = erlang:trace_pattern(on_load, false, [local]),
  773:     ?line {traced,false} = erlang:trace_info(on_load, traced),
  774:     ?line {match_spec,false} = erlang:trace_info(on_load, match_spec),
  775: 
  776:     ?line Pam1 = [{[],[],[{message,false}]}],
  777:     ?line 0 = erlang:trace_pattern(on_load, Pam1),
  778:     ?line {traced,global} = erlang:trace_info(on_load, traced),
  779:     ?line {match_spec,Pam1} = erlang:trace_info(on_load, match_spec),
  780: 
  781:     ?line 0 = erlang:trace_pattern(on_load, true, [local]),
  782:     ?line 0 = erlang:trace_pattern(on_load, false, [local]),
  783: 
  784:     ok.
  785: 
  786: 
  787: 
  788: deep_exception(doc) -> "Test the new exception trace.";
  789: deep_exception(suite) -> [];
  790: deep_exception(Config) when is_list(Config) ->
  791:     deep_exception().
  792: 
  793: deep_exception() ->
  794:     ?line start_tracer(),
  795:     ?line Self = self(),
  796:     ?line N = 200000,
  797:     ?line LongImproperList = seq(1, N-1, N),
  798:     
  799:     Prog = [{'_',[],[{exception_trace}]}],
  800: %%    ?line 1 = trace_pid(Self, true, [call]),
  801:     ?line 1 = trace_func({?MODULE,deep,'_'}, Prog),
  802:     ?line 1 = trace_func({?MODULE,deep_1,'_'}, Prog),
  803:     ?line 1 = trace_func({?MODULE,deep_2,'_'}, Prog),
  804:     ?line 1 = trace_func({?MODULE,deep_3,'_'}, Prog),
  805:     ?line 1 = trace_func({?MODULE,deep_4,'_'}, Prog),
  806:     ?line 1 = trace_func({?MODULE,deep_5,'_'}, Prog),
  807:     ?line 1 = trace_func({?MODULE,id,'_'}, Prog),
  808:     ?line 1 = trace_func({erlang,'++','_'}, Prog),
  809:     ?line 1 = trace_func({erlang,exit,1}, Prog),
  810:     ?line 1 = trace_func({erlang,throw,1}, Prog),
  811:     ?line 2 = trace_func({erlang,error,'_'}, Prog),
  812:     ?line 1 = trace_func({lists,reverse,2}, Prog),
  813: 
  814:     ?line deep_exception(?LINE, exit, [paprika], 1, 
  815: 			 [{trace,Self,call,{erlang,exit,[paprika]}},
  816: 			  {trace,Self,exception_from,{erlang,exit,1},
  817: 			   {exit,paprika}}], 
  818: 			 exception_from, {exit,paprika}),
  819:     ?line deep_exception(?LINE, throw, [3.14], 2, 
  820: 			 [{trace,Self,call,{erlang,throw,[3.14]}},
  821: 			  {trace,Self,exception_from,{erlang,throw,1},
  822: 			   {throw,3.14}}], 
  823: 			 exception_from, {throw,3.14}),
  824:     ?line deep_exception(?LINE, error, [{paprika}], 3, 
  825: 			 [{trace,Self,call,{erlang,error,[{paprika}]}},
  826: 			  {trace,Self,exception_from,{erlang,error,1},
  827: 			   {error,{paprika}}}], 
  828: 			 exception_from, {error,{paprika}}),
  829:     ?line deep_exception(?LINE, error, ["{paprika}",[]], 3, 
  830: 			 [{trace,Self,call,{erlang,error,["{paprika}",[]]}},
  831: 			  {trace,Self,exception_from,{erlang,error,2},
  832: 			   {error,"{paprika}"}}], 
  833: 			 exception_from, {error,"{paprika}"}),
  834:     ?line deep_exception(?LINE, id, [broccoli], 4, [], 
  835: 			 return_from, broccoli),
  836:     ?line deep_exception(
  837: 	    ?LINE, append, [1,2], 5,
  838: 	    [{trace,Self,call,{erlang,'++',[1,2]}},
  839: 	     {trace,Self,exception_from,{erlang,'++',2},{error,badarg}}],
  840: 	    exception_from, {error,badarg}),
  841:     ?line deep_exception(?LINE, '=', [1,2], 6, [],
  842: 			 exception_from, {error,{badmatch,2}}),
  843:     %%
  844:     ?line io:format("== Subtest: ~w", [?LINE]),
  845:     ?line try lists:reverse(LongImproperList, []) of
  846: 	      R1 -> test_server:fail({returned,abbr(R1)})
  847: 	  catch error:badarg -> ok
  848: 	  end,
  849:     ?line expect(fun ({trace,S,call,{lists,reverse,[L1,L2]}})
  850: 		     when is_list(L1), is_list(L2), S == Self ->
  851: 			 next;
  852: 		     ({trace,S,exception_from,
  853: 		       {lists,reverse,2},{error,badarg}}) 
  854: 		     when S == Self ->
  855: 			 expected;
  856: 		     ('_') ->
  857: 			 {trace,Self,exception_from,
  858: 			  {lists,reverse,2},{error,badarg}};
  859: 		     (_) ->
  860: 			 {unexpected,
  861: 			  {trace,Self,exception_from,
  862: 			   {lists,reverse,2},{error,badarg}}}
  863: 		 end),
  864:     ?line deep_exception(?LINE, deep_5, [1,2], 7, 
  865: 			 [{trace,Self,call,{erlang,error,[undef]}},
  866: 			  {trace,Self,exception_from,{erlang,error,1},
  867: 			   {error,undef}}],
  868: 			 exception_from, {error,undef}),
  869:     ?line deep_exception(?LINE, deep_5, [undef], 8, 
  870: 			 [{trace,Self,call,{?MODULE,deep_5,[undef]}},
  871: 			  {trace,Self,exception_from,{?MODULE,deep_5,1},
  872: 			   {error,function_clause}}],
  873: 			 exception_from, {error,function_clause}),
  874:     
  875:     %% Apply
  876:     %%
  877:     ?line deep_exception(?LINE, apply, [erlang,error,[[mo|rot]]], 1, 
  878: 			 [{trace,Self,call,{erlang,error,[[mo|rot]]}},
  879: 			  {trace,Self,exception_from,{erlang,error,1},
  880: 			   {error,[mo|rot]}}],
  881: 			 exception_from, {error,[mo|rot]}),
  882:     ?line deep_exception(?LINE, apply, [erlang,error,[[mo|"rot"],[]]], 1, 
  883: 			 [{trace,Self,call,{erlang,error,[[mo|"rot"],[]]}},
  884: 			  {trace,Self,exception_from,{erlang,error,2},
  885: 			   {error,[mo|"rot"]}}],
  886: 			 exception_from, {error,[mo|"rot"]}),
  887:     ?line Morot = make_ref(),
  888:     ?line deep_exception(?LINE, apply, [erlang,throw,[Morot]], 3, 
  889: 			 [{trace,Self,call,{erlang,throw,[Morot]}},
  890: 			  {trace,Self,exception_from,{erlang,throw,1},
  891: 			   {throw,Morot}}],
  892: 			 exception_from, {throw,Morot}),
  893:     ?line deep_exception(?LINE, apply, [erlang,exit,[["morot"|Morot]]], 2, 
  894: 			 [{trace,Self,call,{erlang,exit,[["morot"|Morot]]}},
  895: 			  {trace,Self,exception_from,{erlang,exit,1},
  896: 			   {exit,["morot"|Morot]}}],
  897: 			 exception_from, {exit,["morot"|Morot]}),
  898:     ?line deep_exception(
  899: 	    ?LINE, apply, [?MODULE,id,[spenat]], 4,
  900: 	    [{trace,Self,call,{?MODULE,id,[spenat]}},
  901: 	     {trace,Self,return_from,{?MODULE,id,1},spenat}],
  902: 	    return_from, spenat),
  903:     ?line deep_exception(
  904: 	    ?LINE, apply, [erlang,'++',[1,2]], 5,
  905: 	    [{trace,Self,call,{erlang,'++',[1,2]}},
  906: 	     {trace,Self,exception_from,{erlang,'++',2},{error,badarg}}],
  907: 	    exception_from, {error,badarg}),
  908:     ?line io:format("== Subtest: ~w", [?LINE]),
  909:     ?line try apply(lists, reverse, [LongImproperList, []]) of
  910: 	      R2 -> test_server:fail({returned,abbr(R2)})
  911: 	  catch error:badarg -> ok
  912: 	  end,
  913:     ?line expect(fun ({trace,S,call,{lists,reverse,[L1,L2]}})
  914: 		     when is_list(L1), is_list(L2), S == Self ->
  915: 			 next;
  916: 		     ({trace,S,exception_from,
  917: 		       {lists,reverse,2},{error,badarg}}) 
  918: 		     when S == Self ->
  919: 			 expected;
  920: 		     ('_') ->
  921: 			 {trace,Self,exception_from,
  922: 			  {lists,reverse,2},{error,badarg}};
  923: 		     (_) ->
  924: 			 {unexpected,
  925: 			  {trace,Self,exception_from,
  926: 			   {lists,reverse,2},{error,badarg}}}
  927: 		 end),
  928:     ?line deep_exception(?LINE, apply, [?MODULE,deep_5,[1,2]], 7, 
  929: 			 [{trace,Self,call,{erlang,error,[undef]}},
  930: 			  {trace,Self,exception_from,{erlang,error,1},
  931: 			   {error,undef}}],
  932: 			 exception_from, {error,undef}),
  933:     ?line deep_exception(?LINE, apply, [?MODULE,deep_5,[undef]], 8, 
  934: 			 [{trace,Self,call,{?MODULE,deep_5,[undef]}},
  935: 			  {trace,Self,exception_from,{?MODULE,deep_5,1},
  936: 			   {error,function_clause}}],
  937: 			 exception_from, {error,function_clause}),
  938:     %% Apply of fun
  939:     %%
  940:     ?line deep_exception(?LINE, apply, 
  941: 			 [fun () -> 
  942: 				  erlang:error([{"palsternacka",3.14},17]) 
  943: 			  end, []], 1, 
  944: 			 [{trace,Self,call,
  945: 			   {erlang,error,[[{"palsternacka",3.14},17]]}},
  946: 			  {trace,Self,exception_from,{erlang,error,1},
  947: 			   {error,[{"palsternacka",3.14},17]}}],
  948: 			 exception_from, {error,[{"palsternacka",3.14},17]}),
  949:     ?line deep_exception(?LINE, apply, 
  950: 			 [fun () -> 
  951: 				  erlang:error(["palsternacka",17], []) 
  952: 			  end, []], 1, 
  953: 			 [{trace,Self,call,
  954: 			   {erlang,error,[["palsternacka",17],[]]}},
  955: 			  {trace,Self,exception_from,{erlang,error,2},
  956: 			   {error,["palsternacka",17]}}],
  957: 			 exception_from, {error,["palsternacka",17]}),
  958:     ?line deep_exception(?LINE, apply, 
  959: 			 [fun () -> erlang:throw(Self) end, []], 2, 
  960: 			 [{trace,Self,call,{erlang,throw,[Self]}},
  961: 			  {trace,Self,exception_from,{erlang,throw,1},
  962: 			   {throw,Self}}],
  963: 			 exception_from, {throw,Self}),
  964:     ?line deep_exception(?LINE, apply, 
  965: 			 [fun () -> 
  966: 				  erlang:exit({1,2,3,4,[5,palsternacka]})
  967: 			  end, []], 3,
  968: 			 [{trace,Self,call,
  969: 			   {erlang,exit,[{1,2,3,4,[5,palsternacka]}]}},
  970: 			  {trace,Self,exception_from,{erlang,exit,1},
  971: 			   {exit,{1,2,3,4,[5,palsternacka]}}}],
  972: 			 exception_from, {exit,{1,2,3,4,[5,palsternacka]}}),
  973:     ?line deep_exception(?LINE, apply, 
  974: 			 [fun () -> ?MODULE:id(bladsallad) end, []], 4,
  975: 			 [{trace,Self,call,{?MODULE,id,[bladsallad]}},
  976: 			  {trace,Self,return_from,{?MODULE,id,1},bladsallad}],
  977: 			 return_from, bladsallad),
  978:     ?line deep_exception(?LINE, apply, 
  979: 			 [fun (A, B) -> A ++ B end, [1,2]], 5,
  980: 			 [{trace,Self,call,{erlang,'++',[1,2]}},
  981: 			  {trace,Self,exception_from,
  982: 			   {erlang,'++',2},{error,badarg}}],
  983: 			 exception_from, {error,badarg}),
  984:     ?line deep_exception(?LINE, apply, [fun (A, B) -> A = B end, [1,2]], 6, 
  985: 			 [],
  986: 			 exception_from, {error,{badmatch,2}}),
  987:     ?line io:format("== Subtest: ~w", [?LINE]),
  988:     ?line try apply(fun() -> lists:reverse(LongImproperList, []) end, []) of
  989: 	      R3 -> test_server:fail({returned,abbr(R3)})
  990: 	  catch error:badarg -> ok
  991: 	  end,
  992:     ?line expect(fun ({trace,S,call,{lists,reverse,[L1,L2]}})
  993: 		     when is_list(L1), is_list(L2), S == Self ->
  994: 			 next;
  995: 		     ({trace,S,exception_from,
  996: 		       {lists,reverse,2},{error,badarg}}) 
  997: 		     when S == Self ->
  998: 			 expected;
  999: 		     ('_') ->
 1000: 			 {trace,Self,exception_from,
 1001: 			  {lists,reverse,2},{error,badarg}};
 1002: 		     (_) ->
 1003: 			 {unexpected,
 1004: 			  {trace,Self,exception_from,
 1005: 			   {lists,reverse,2},{error,badarg}}}
 1006: 		 end),
 1007:     ?line deep_exception(?LINE, apply, 
 1008: 			 [fun () -> ?MODULE:deep_5(1,2) end, []], 7, 
 1009: 			 [{trace,Self,call,{erlang,error,[undef]}},
 1010: 			  {trace,Self,exception_from,{erlang,error,1},
 1011: 			   {error,undef}}],
 1012: 			 exception_from, {error,undef}),
 1013:     ?line deep_exception(?LINE, apply, 
 1014: 			 [fun () -> ?MODULE:deep_5(undef) end, []], 8, 
 1015: 			 [{trace,Self,call,{?MODULE,deep_5,[undef]}},
 1016: 			  {trace,Self,exception_from,{?MODULE,deep_5,1},
 1017: 			   {error,function_clause}}],
 1018: 			 exception_from, {error,function_clause}),
 1019:     
 1020:     ?line trace_func({?MODULE,'_','_'}, false),
 1021:     ?line trace_func({erlang,'_','_'}, false),
 1022:     ?line trace_func({lists,'_','_'}, false),
 1023:     ?line expect(),
 1024:     ?line ok.
 1025: 
 1026: 
 1027: deep_exception(Line, B, Q, N, Extra, Tag, R) ->
 1028:     ?line Self = self(),
 1029:     ?line io:format("== Subtest: ~w", [Line]),
 1030:     ?line Result = ?MODULE:deep(N, B, Q),
 1031:     ?line Result = deep_expect(Self, B, Q, N, Extra, Tag, R).
 1032: 
 1033: deep_expect(Self, B, Q, N, Extra, Tag, R) ->
 1034:     ?line expect({trace,Self,call,{?MODULE,deep,[N,B,Q]}}),
 1035:     ?line Result = deep_expect_N(Self, B, Q, N, Extra, Tag, R),
 1036:     ?line expect({trace,Self,return_from,{?MODULE,deep,3},Result}),
 1037:     ?line Result.
 1038: 
 1039: deep_expect_N(Self, B, Q, N, Extra, Tag, R) ->
 1040:     deep_expect_N(Self, B, Q, N, Extra, Tag, R, N).
 1041: 
 1042: deep_expect_N(Self, B, Q, N, Extra, Tag, R, J) when J > 0 ->
 1043:     ?line expect({trace,Self,call,{?MODULE,deep_1,[J,B,Q]}}),
 1044:     ?line deep_expect_N(Self, B, Q, N, Extra, Tag, R, J-1);
 1045: deep_expect_N(Self, B, Q, N, Extra, Tag, R, 0) ->
 1046:     ?line expect({trace,Self,call,{?MODULE,deep_2,[B,Q]}}),
 1047:     ?line expect({trace,Self,call,{?MODULE,deep_3,[B,Q]}}),
 1048:     ?line expect({trace,Self,return_from,{?MODULE,deep_3,2},{B,Q}}),
 1049:     ?line expect({trace,Self,call,{?MODULE,deep_4,[{B,Q}]}}),
 1050:     ?line expect({trace,Self,call,{?MODULE,id,[{B,Q}]}}),
 1051:     ?line expect({trace,Self,return_from,{?MODULE,id,1},{B,Q}}),
 1052:     ?line deep_expect_Extra(Self, N, Extra, Tag, R),
 1053:     ?line expect({trace,Self,Tag,{?MODULE,deep_4,1},R}),
 1054:     ?line expect({trace,Self,Tag,{?MODULE,deep_2,2},R}),
 1055:     ?line deep_expect_N(Self, N, Tag, R).
 1056: 
 1057: deep_expect_Extra(Self, N, [E|Es], Tag, R) ->
 1058:     ?line expect(E),
 1059:     ?line deep_expect_Extra(Self, N, Es, Tag, R);
 1060: deep_expect_Extra(_Self, _N, [], _Tag, _R) ->
 1061:     ?line ok.
 1062: 
 1063: deep_expect_N(Self, N, Tag, R) when N > 0 ->
 1064:     ?line expect({trace,Self,Tag,{?MODULE,deep_1,3},R}),
 1065:     ?line deep_expect_N(Self, N-1, Tag, R);
 1066: deep_expect_N(_Self, 0, return_from, R) ->
 1067:     ?line {value,R};
 1068: deep_expect_N(_Self, 0, exception_from, R) ->
 1069:     ?line R.
 1070: 
 1071: 
 1072: 
 1073: exception_nocatch(doc) -> "Test the new exception trace.";
 1074: exception_nocatch(suite) -> [];
 1075: exception_nocatch(Config) when is_list(Config) ->
 1076:     exception_nocatch().
 1077: 
 1078: exception_nocatch() ->
 1079:     Deep4LocThrow = get_deep_4_loc({throw,[42]}),
 1080:     Deep4LocError = get_deep_4_loc({error,[42]}),
 1081:     Deep4LocBadmatch = get_deep_4_loc({'=',[a,b]}),
 1082: 
 1083:     Prog = [{'_',[],[{exception_trace}]}],
 1084:     ?line 1 = erlang:trace_pattern({?MODULE,deep_1,'_'}, Prog),
 1085:     ?line 1 = erlang:trace_pattern({?MODULE,deep_2,'_'}, Prog),
 1086:     ?line 1 = erlang:trace_pattern({?MODULE,deep_3,'_'}, Prog),
 1087:     ?line 1 = erlang:trace_pattern({?MODULE,deep_4,'_'}, Prog),
 1088:     ?line 1 = erlang:trace_pattern({?MODULE,deep_5,'_'}, Prog),
 1089:     ?line 1 = erlang:trace_pattern({?MODULE,id,'_'}, Prog),
 1090:     ?line 1 = erlang:trace_pattern({erlang,exit,1}, Prog),
 1091:     ?line 1 = erlang:trace_pattern({erlang,throw,1}, Prog),
 1092:     ?line 2 = erlang:trace_pattern({erlang,error,'_'}, Prog),
 1093:     ?line Q1 = {make_ref(),Prog},
 1094:     ?line T1 = 
 1095: 	exception_nocatch(?LINE, exit, [Q1], 3, 
 1096: 			  [{trace,t1,call,{erlang,exit,[Q1]}},
 1097: 			   {trace,t1,exception_from,{erlang,exit,1},
 1098: 			    {exit,Q1}}],
 1099: 			  exception_from, {exit,Q1}),
 1100:     ?line expect({trace,T1,exit,Q1}),
 1101:     ?line Q2 = {cake,14.125},
 1102:     ?line T2 = 
 1103: 	exception_nocatch(?LINE, throw, [Q2], 2, 
 1104: 			  [{trace,t2,call,{erlang,throw,[Q2]}},
 1105: 			   {trace,t2,exception_from,{erlang,throw,1},
 1106: 			    {error,{nocatch,Q2}}}],
 1107: 			  exception_from, {error,{nocatch,Q2}}),
 1108:     ?line expect({trace,T2,exit,{{nocatch,Q2},[{erlang,throw,[Q2],[]},
 1109: 					       {?MODULE,deep_4,1,
 1110: 						Deep4LocThrow}]}}),
 1111:     ?line Q3 = {dump,[dump,{dump}]},
 1112:     ?line T3 = 
 1113: 	exception_nocatch(?LINE, error, [Q3], 4, 
 1114: 			  [{trace,t3,call,{erlang,error,[Q3]}},
 1115: 			   {trace,t3,exception_from,{erlang,error,1},
 1116: 			    {error,Q3}}],
 1117: 			  exception_from, {error,Q3}),
 1118:     ?line expect({trace,T3,exit,{Q3,[{erlang,error,[Q3],[]},
 1119: 				     {?MODULE,deep_4,1,Deep4LocError}]}}),
 1120:     ?line T4 = 
 1121: 	exception_nocatch(?LINE, '=', [17,4711], 5, [], 
 1122: 			  exception_from, {error,{badmatch,4711}}),
 1123:     ?line expect({trace,T4,exit,{{badmatch,4711},
 1124: 				 [{?MODULE,deep_4,1,Deep4LocBadmatch}]}}),
 1125:     %%
 1126:     ?line erlang:trace_pattern({?MODULE,'_','_'}, false),
 1127:     ?line erlang:trace_pattern({erlang,'_','_'}, false),
 1128:     ?line expect(),
 1129:     ?line ok.
 1130: 
 1131: get_deep_4_loc(Arg) ->
 1132:     try
 1133: 	deep_4(Arg),
 1134: 	?t:fail(should_not_return_to_here)
 1135:     catch
 1136: 	_:_ ->
 1137: 	    [{?MODULE,deep_4,1,Loc0}|_] = erlang:get_stacktrace(),
 1138: 	    Loc0
 1139:     end.
 1140: 
 1141: exception_nocatch(Line, B, Q, N, Extra, Tag, R) ->
 1142:     ?line io:format("== Subtest: ~w", [Line]),
 1143:     ?line Go = make_ref(),
 1144:     ?line Tracee = 
 1145: 	spawn(fun () ->
 1146: 		      receive
 1147: 			  Go ->
 1148: 			      deep_1(N, B, Q)
 1149: 		      end
 1150: 	      end),
 1151:     ?line 1 = erlang:trace(Tracee, true, [call,return_to,procs]),
 1152:     ?line Tracee ! Go,
 1153:     ?line deep_expect_N(Tracee, B, Q, N-1, 
 1154: 			[setelement(2, T, Tracee) || T <- Extra], Tag, R),
 1155:     ?line Tracee.
 1156: 
 1157: %% Make sure that code that uses the optimized bit syntax matching
 1158: %% can be traced without crashing the emulator. (Actually, it seems
 1159: %% that we can't trigger the bug using external call trace, but we
 1160: %% will keep the test case anyway.)
 1161: 
 1162: bit_syntax(Config) when is_list(Config) ->
 1163:     ?line start_tracer(),
 1164:     ?line 1 = trace_func({?MODULE,bs_sum_a,'_'}, []),
 1165:     ?line 1 = trace_func({?MODULE,bs_sum_b,'_'}, []),
 1166: 
 1167:     ?line 6 = call_bs_sum_a(<<1,2,3>>),
 1168:     ?line 10 = call_bs_sum_b(<<1,2,3,4>>),
 1169: 
 1170:     ?line trace_func({?MODULE,'_','_'}, false),
 1171:     ?line erlang:trace_delivered(all),
 1172:     receive
 1173: 	{trace_delivered,_,_} -> ok
 1174:     end,
 1175:     
 1176:     Self = self(),
 1177:     ?line expect({trace,Self,call,{?MODULE,bs_sum_a,[<<2,3>>,1]}}),
 1178:     ?line expect({trace,Self,call,{?MODULE,bs_sum_b,[1,<<2,3,4>>]}}),
 1179: 
 1180:     ok.
 1181: 
 1182: call_bs_sum_a(<<H,T/binary>>) ->
 1183:     ?MODULE:bs_sum_a(T, H).
 1184: 
 1185: call_bs_sum_b(<<H,T/binary>>) ->
 1186:     ?MODULE:bs_sum_b(H, T).
 1187: 
 1188: bs_sum_a(<<H,T/binary>>, Acc) -> bs_sum_a(T, H+Acc);
 1189: bs_sum_a(<<>>, Acc) -> Acc.
 1190: 
 1191: bs_sum_b(Acc, <<H,T/binary>>) -> bs_sum_b(H+Acc, T);
 1192: bs_sum_b(Acc, <<>>) -> Acc.
 1193:     
 1194: 
 1195: 
 1196: 
 1197: %%% Help functions.
 1198: 
 1199: expect() ->
 1200:     case flush() of
 1201: 	[] -> ok;
 1202: 	Msgs ->
 1203: 	    test_server:fail({unexpected,abbr(Msgs)})
 1204:     end.
 1205: 
 1206: expect({trace_ts,Pid,Type,MFA,Term,ts}=Message) ->
 1207:     receive
 1208: 	M ->
 1209: 	    case M of
 1210: 		{trace_ts,Pid,Type,MFA,Term,Ts}=MessageTs ->
 1211: 		    ok = io:format("Expected and got ~p", [abbr(MessageTs)]),
 1212: 		    Ts;
 1213: 		_ ->
 1214: 		    io:format("Expected ~p; got ~p", [abbr(Message),abbr(M)]),
 1215: 		    test_server:fail({unexpected,abbr([M|flush()])})
 1216: 	    end
 1217:     after 5000 ->
 1218: 	    io:format("Expected ~p; got nothing", [abbr(Message)]),
 1219: 	    test_server:fail(no_trace_message)
 1220:     end;
 1221: expect({trace_ts,Pid,Type,MFA,ts}=Message) ->
 1222:     receive
 1223: 	M ->
 1224: 	    case M of
 1225: 		{trace_ts,Pid,Type,MFA,Ts} ->
 1226: 		    ok = io:format("Expected and got ~p", [abbr(M)]),
 1227: 		    Ts;
 1228: 		_ ->
 1229: 		    io:format("Expected ~p; got ~p", [abbr(Message),abbr(M)]),
 1230: 		    test_server:fail({unexpected,abbr([M|flush()])})
 1231: 	    end
 1232:     after 5000 ->
 1233: 	    io:format("Expected ~p; got nothing", [abbr(Message)]),
 1234: 	    test_server:fail(no_trace_message)
 1235:     end;
 1236: expect(Validator) when is_function(Validator) ->
 1237:     receive
 1238: 	M ->
 1239: 	    case Validator(M) of
 1240: 		expected ->
 1241: 		    ok = io:format("Expected and got ~p", [abbr(M)]);
 1242:  		next ->
 1243:  		    ok = io:format("Expected and got ~p", [abbr(M)]),
 1244:  		    expect(Validator);
 1245:  		{unexpected,Message} ->
 1246:  		    io:format("Expected ~p; got ~p", [abbr(Message),abbr(M)]),
 1247:  		    test_server:fail({unexpected,abbr([M|flush()])})
 1248: 	    end
 1249:     after 5000 ->
 1250: 	    io:format("Expected ~p; got nothing", [abbr(Validator('_'))]),
 1251: 	    test_server:fail(no_trace_message)
 1252:     end;
 1253: expect(Message) ->
 1254:     receive
 1255: 	M ->
 1256: 	    case M of
 1257: 		Message ->
 1258: 		    ok = io:format("Expected and got ~p", [abbr(Message)]);
 1259: 		Other ->
 1260: 		    io:format("Expected ~p; got ~p", 
 1261: 			      [abbr(Message),abbr(Other)]),
 1262: 		    test_server:fail({unexpected,abbr([Other|flush()])})
 1263: 	    end
 1264:     after 5000 ->
 1265: 	    io:format("Expected ~p; got nothing", [abbr(Message)]),
 1266: 	    test_server:fail(no_trace_message)
 1267:     end.
 1268: 
 1269: trace_info(What, Key) ->
 1270:     get(tracer) ! {apply,self(),{erlang,trace_info,[What,Key]}},
 1271:     Res = receive
 1272: 	      {apply_result,Result} -> Result
 1273: 	  end,
 1274:     ok = io:format("erlang:trace_info(~p, ~p) -> ~p",
 1275: 		   [What,Key,Res]),
 1276:     Res.
 1277:     
 1278: trace_func(MFA, MatchSpec) ->
 1279:     trace_func(MFA, MatchSpec, []).
 1280: trace_func(MFA, MatchSpec, Flags) ->
 1281:     get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA, MatchSpec, Flags]}},
 1282:     Res = receive
 1283: 	      {apply_result,Result} -> Result
 1284: 	  end,
 1285:     ok = io:format("trace_pattern(~p, ~p, ~p) -> ~p", [MFA,MatchSpec,Flags,Res]),
 1286:     Res.
 1287: 
 1288: trace_pid(Pid, On, Flags) ->
 1289:     get(tracer) ! {apply,self(),{erlang,trace,[Pid,On,Flags]}},
 1290:     Res = receive
 1291: 	      {apply_result,Result} -> Result
 1292: 	  end,
 1293:     ok = io:format("trace(~p, ~p, ~p) -> ~p", [Pid,On,Flags,Res]),
 1294:     Res.
 1295: 
 1296: start_tracer() ->
 1297:     Self = self(),
 1298:     put(tracer, spawn(fun() -> tracer(Self) end)),
 1299:     get(tracer).
 1300: 
 1301: start_tracer_loop() ->
 1302:     Self = self(),
 1303:     put(tracer, spawn(fun() -> tracer_loop(Self) end)),
 1304:     get(tracer).
 1305: 
 1306: tracer(RelayTo) ->
 1307:     erlang:trace(RelayTo, true, [call]),
 1308:     tracer_loop(RelayTo).
 1309: 
 1310: tracer_loop(RelayTo) ->
 1311:     receive
 1312: 	{apply,From,{M,F,A}} ->
 1313: 	    From ! {apply_result,apply(M, F, A)},
 1314: 	    tracer_loop(RelayTo);
 1315: 	Msg ->
 1316: 	    RelayTo ! Msg,
 1317: 	    tracer_loop(RelayTo)
 1318:     end.
 1319: 
 1320: id(I) -> I.
 1321: 
 1322: deep(N, Class, Reason) ->
 1323:     try ?MODULE:deep_1(N, Class, Reason) of
 1324: 	Value -> {value,Value}
 1325:     catch C:R -> {C,R}
 1326:     end.
 1327: 
 1328: deep_1(1, Class, Reason) ->
 1329:     ?MODULE:deep_2(Class, Reason);
 1330: deep_1(N, Class, Reason) when is_integer(N), N > 1 ->
 1331:     ?MODULE:deep_1(N-1, Class, Reason).
 1332: 
 1333: deep_2(Class, Reason) ->
 1334:     ?MODULE:deep_4(?MODULE:deep_3(Class, Reason)).
 1335: 
 1336: deep_3(Class, Reason) ->
 1337:     {Class,Reason}.
 1338: 
 1339: deep_4(CR) ->
 1340:     case ?MODULE:id(CR) of
 1341: 	{exit,[Reason]} ->
 1342: 	    erlang:exit(Reason);
 1343: 	{throw,[Reason]} ->
 1344: 	    erlang:throw(Reason);
 1345: 	{error,[Reason,Arglist]} ->
 1346: 	    erlang:error(Reason, Arglist);
 1347: 	{error,[Reason]} ->
 1348: 	    erlang:error(Reason);
 1349: 	{id,[Reason]} ->
 1350: 	    Reason;
 1351: 	{reverse,[A,B]} ->
 1352: 	    lists:reverse(A, B);
 1353: 	{append,[A,B]} ->
 1354: 	    A ++ B;
 1355: 	{apply,[Fun,Args]} ->
 1356: 	    erlang:apply(Fun, Args);
 1357: 	{apply,[M,F,Args]} ->
 1358: 	    erlang:apply(M, F, Args);
 1359: 	{deep_5,[A,B]} ->
 1360: 	    ?MODULE:deep_5(A, B);
 1361: 	{deep_5,[A]} ->
 1362: 	    ?MODULE:deep_5(A);
 1363: 	{'=',[A,B]} ->
 1364: 	    A = B
 1365:     end.
 1366: 
 1367: deep_5(A) when is_integer(A) ->
 1368:     A.
 1369: 
 1370: flush() ->
 1371:     receive X ->
 1372: 	    [X|flush()]
 1373:     after 1000 ->
 1374: 	    []
 1375:     end.
 1376: 
 1377: %% Abbreviate large complex terms
 1378: abbr(Term) ->
 1379:     abbr(Term, 20).
 1380: %%
 1381: abbr(Tuple, N) when is_tuple(Tuple) ->
 1382:     abbr_tuple(Tuple, 1, N, []);
 1383: abbr(List, N) when is_list(List) ->
 1384:     abbr_list(List, N, []);
 1385: abbr(Term, _) -> Term.
 1386: %%
 1387: abbr_tuple(_, _, 0, R) ->
 1388:     list_to_tuple(reverse(R, ['...']));
 1389: abbr_tuple(Tuple, J, N, R) when J =< size(Tuple) ->
 1390:     M = N-1,
 1391:     abbr_tuple(Tuple, J+1, M, [abbr(element(J, Tuple), M)|R]);
 1392: abbr_tuple(_, _, _, R) ->
 1393:     list_to_tuple(reverse(R)).
 1394: %%
 1395: abbr_list(_, 0, R) ->
 1396:     case io_lib:printable_list(R) of
 1397: 	true ->
 1398: 	    reverse(R, "...");
 1399: 	false ->
 1400: 	    reverse(R, '...')
 1401:     end;
 1402: abbr_list([H|T], N, R) ->
 1403:     M = N-1,
 1404:     abbr_list(T, M, [abbr(H, M)|R]);
 1405: abbr_list(T, _, R) ->
 1406:     reverse(R, T).
 1407: 
 1408: %% Lean and mean list functions
 1409: 
 1410: %% Do not build garbage
 1411: seq(M, N, R) when M =< N ->
 1412:     seq(M, N-1, [N|R]);
 1413: seq(_, _, R) -> R.
 1414: 
 1415: %% lists:reverse can not be called since it is traced
 1416: reverse(L) ->
 1417:     reverse(L, []).
 1418: %%
 1419: reverse([], R) -> R;
 1420: reverse([H|T], R) ->
 1421:     reverse(T, [H|R]).