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]).