1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1999-2013. 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: 20: -module(match_spec_SUITE). 21: 22: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 23: init_per_group/2,end_per_group/2, not_run/1]). 24: -export([test_1/1, test_2/1, test_3/1, bad_match_spec_bin/1, 25: trace_control_word/1, silent/1, silent_no_ms/1, silent_test/1, 26: ms_trace2/1, ms_trace3/1, boxed_and_small/1, 27: destructive_in_test_bif/1, guard_exceptions/1, 28: unary_plus/1, unary_minus/1, moving_labels/1]). 29: -export([fpe/1]). 30: -export([otp_9422/1]). 31: -export([faulty_seq_trace/1, do_faulty_seq_trace/0]). 32: -export([runner/2, loop_runner/3]). 33: -export([f1/1, f2/2, f3/2, fn/1, fn/2, fn/3]). 34: -export([do_boxed_and_small/0]). 35: 36: % This test suite assumes that tracing in general works. What we test is 37: % the match spec functionality. 38: 39: -include_lib("test_server/include/test_server.hrl"). 40: 41: -export([init_per_testcase/2, end_per_testcase/2]). 42: 43: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 44: Dog=?t:timetrap(?t:seconds(10)), 45: [{watchdog, Dog}|Config]. 46: 47: end_per_testcase(_Func, Config) -> 48: Dog=?config(watchdog, Config), 49: ?t:timetrap_cancel(Dog). 50: 51: 52: suite() -> [{ct_hooks,[ts_install_cth]}]. 53: 54: all() -> 55: case test_server:is_native(match_spec_SUITE) of 56: false -> 57: [test_1, test_2, test_3, bad_match_spec_bin, 58: trace_control_word, silent, silent_no_ms, silent_test, ms_trace2, 59: ms_trace3, boxed_and_small, destructive_in_test_bif, 60: guard_exceptions, unary_plus, unary_minus, fpe, 61: moving_labels, 62: faulty_seq_trace, 63: otp_9422]; 64: true -> [not_run] 65: end. 66: 67: groups() -> 68: []. 69: 70: init_per_suite(Config) -> 71: Config. 72: 73: end_per_suite(_Config) -> 74: ok. 75: 76: init_per_group(_GroupName, Config) -> 77: Config. 78: 79: end_per_group(_GroupName, Config) -> 80: Config. 81: 82: 83: not_run(Config) when is_list(Config) -> 84: {skipped, "Native Code"}. 85: 86: test_1(doc) -> 87: [""]; 88: test_1(suite) -> []; 89: test_1(Config) when is_list(Config) -> 90: ?line tr(fun() -> ?MODULE:f1(a) end, 91: {?MODULE, f1, 1}, 92: [], 93: [{call, {?MODULE, f1, [a]}}]), 94: 95: ?line tr(fun() -> ?MODULE:f2(a, a) end, 96: {?MODULE, f2, 2}, 97: [{['$1','$1'],[{is_atom, '$1'}],[]}], 98: [{call, {?MODULE, f2, [a, a]}}]), 99: 100: ?line tr(fun() -> ?MODULE:f2(a, a) end, 101: {?MODULE, f2, 2}, 102: [{['$1','$1'],[{is_atom, '$1'}],[{message, false}]}], 103: []), 104: 105: ?line tr(fun() -> ?MODULE:f2(a, a) end, 106: {?MODULE, f2, 2}, 107: [{['$1','$1'],[{is_atom, '$1'}],[{message, 4711}]}], 108: [{call, {?MODULE, f2, [a, a]}, 4711}]), 109: 110: Ref = make_ref(), 111: ?line tr(fun() -> ?MODULE:f2(Ref, Ref) end, 112: {?MODULE, f2, 2}, 113: [{[Ref,'$1'],[{is_reference, '$1'}],[{message, 4711}]}], 114: [{call, {?MODULE, f2, [Ref, Ref]}, 4711}]), 115: ?line tr(fun() -> ?MODULE:f2(Ref, Ref) end, 116: {?MODULE, f2, 2}, 117: [{['$1',Ref],[{is_reference, '$1'}],[{message, 4711}]}], 118: [{call, {?MODULE, f2, [Ref, Ref]}, 4711}]), 119: 120: ?line tr(fun() -> ?MODULE:f2(a, a) end, 121: {?MODULE, f2, 2}, 122: [{['$0','$0'],[{is_atom, '$0'}],[{message, 4711}]}], 123: [{call, {?MODULE, f2, [a, a]}, 4711}]), 124: 125: ?line tr(fun() -> ?MODULE:f2(a, b) end, 126: {?MODULE, f2, 2}, 127: [{['_','_'],[],[]}], 128: [{call, {?MODULE, f2, [a, b]}}]), 129: 130: ?line tr(fun() -> ?MODULE:f2(a, b) end, 131: {?MODULE, f2, 2}, 132: [{['_','_'],[],[{message, '$_'}]}], 133: [{call, {?MODULE, f2, [a, b]}, [a, b]}]), 134: 135: ?line tr(fun() -> ?MODULE:f2(a, '$_') end, 136: {?MODULE, f2, 2}, 137: [{['$1','$_'],[{is_atom, '$1'}],[]}], 138: [{call, {?MODULE, f2, [a, '$_']}}]), 139: 140: ?line tr(fun() -> ?MODULE:f1({a}) end, 141: {?MODULE, f1, 1}, 142: [{['$1'],[{'==', '$1', {const, {a}}}],[]}], 143: [{call, {?MODULE, f1, [{a}]}}]), 144: 145: ?line tr(fun() -> ?MODULE:f1({a}) end, 146: {?MODULE, f1, 1}, 147: [{['$1'],[{'==', '$1', {{a}}}],[]}], 148: [{call, {?MODULE, f1, [{a}]}}]), 149: 150: %% Undocumented, currently. 151: ?line tr(fun() -> ?MODULE:f2(a, a) end, 152: {?MODULE, f2, 2}, 153: [{['$1','$1'],[{is_atom, '$1'}],[{message, 4711}, 154: {message, true}]}], 155: [{call, {?MODULE, f2, [a, a]}}]), 156: 157: ?line tr(fun() -> ?MODULE:f2(a, a) end, 158: {?MODULE, f2, 2}, 159: [{['$1','$1'],[{is_atom, '$1'}],[{message, 4711}, 160: {message, false}]}], 161: []), 162: 163: ?line tr(fun() -> ?MODULE:f2(a, a) end, 164: {?MODULE, f2, 2}, 165: [{['$1','$1'],[{is_atom, '$1'}],[kakalorum]}], 166: [{call, {?MODULE, f2, [a, a]}}]), 167: 168: % case tr0(fun() -> ?MODULE:f2(a, a) end, 169: % {?MODULE, f2, 2}, 170: % [{['$1','$1'],[{is_atom, '$1'}],[{message, {process_dump}}]}]) of 171: % [{trace, _, call, {?MODULE, f2, [a, a]}, Bin}] -> 172: % erlang:display(binary_to_list(Bin)) 173: % end, 174: 175: % Error cases 176: ?line errchk([{['$1','$1'],[{is_atom, '$1'}],[{banka, kanin}]}]), 177: 178: ok. 179: 180: test_2(doc) -> 181: [""]; 182: test_2(suite) -> []; 183: test_2(Config) when is_list(Config) -> 184: ?line tr(fun() -> ?MODULE:f2(a, a) end, 185: {?MODULE, f2, 2}, 186: [{['$1','$1'],[{is_atom, '$1'}],[{return_trace}]}], 187: [{call, {?MODULE, f2, [a, a]}}, 188: {return_from, {?MODULE, f2, 2}, {a, a}}]), 189: ok. 190: 191: test_3(doc) -> 192: ["Test the enable_trace/2 and caller/0 PAM instructions"]; 193: test_3(suite) -> []; 194: test_3(Config) when is_list(Config) -> 195: ?line Fun1 = fun() -> 196: register(fnoppelklopfer,self()), 197: ?MODULE:f2(a, b), 198: ?MODULE:f2(a, b) 199: end, 200: ?line P1 = spawn(?MODULE, runner, [self(), Fun1]), 201: ?line Pat = [{['$1','$1'],[],[{message, 202: [{enable_trace, P1, call},{caller}]}]}, 203: {['_','_'],[],[{message, 204: [{disable_trace, fnoppelklopfer, call}]}]}], 205: ?line Fun2 = fun() -> ?MODULE:f3(a, a) end, 206: ?line P2 = spawn(?MODULE, runner, [self(), Fun2]), 207: ?line erlang:trace(P2, true, [call]), 208: ?line erlang:trace_pattern({?MODULE, f2, 2}, Pat), 209: ?line collect(P2, [{trace, P2, call, {?MODULE, f2, [a, a]}, [true, 210: {?MODULE,f3,2}]}]), 211: ?line collect(P1, [{trace, P1, call, {?MODULE, f2, [a, b]}, [true]}]), 212: ?line ok. 213: 214: otp_9422(doc) -> []; 215: otp_9422(Config) when is_list(Config) -> 216: Laps = 10000, 217: ?line Fun1 = fun() -> otp_9422_tracee() end, 218: ?line P1 = spawn_link(?MODULE, loop_runner, [self(), Fun1, Laps]), 219: io:format("spawned ~p as tracee\n", [P1]), 220: 221: ?line erlang:trace(P1, true, [call, silent]), 222: 223: ?line Fun2 = fun() -> otp_9422_trace_changer() end, 224: ?line P2 = spawn_link(?MODULE, loop_runner, [self(), Fun2, Laps]), 225: io:format("spawned ~p as trace_changer\n", [P2]), 226: 227: start_collect(P1), 228: start_collect(P2), 229: 230: %%receive after 10*1000 -> ok end, 231: 232: stop_collect(P1), 233: stop_collect(P2, abort), 234: ok. 235: 236: otp_9422_tracee() -> 237: ?MODULE:f1(a), 238: ?MODULE:f1(b), 239: ?MODULE:f1(c). 240: 241: otp_9422_trace_changer() -> 242: Pat1 = [{[a], [], [{enable_trace, arity}]}], 243: ?line erlang:trace_pattern({?MODULE, f1, 1}, Pat1), 244: Pat2 = [{[b], [], [{disable_trace, arity}]}], 245: ?line erlang:trace_pattern({?MODULE, f1, 1}, Pat2). 246: 247: 248: 249: 250: 251: bad_match_spec_bin(Config) when is_list(Config) -> 252: {'EXIT',{badarg,_}} = (catch ets:match_spec_run([1], <<>>)), 253: B0 = <<1,2>>, 254: {B,_} = split_binary(B0, 0), 255: {'EXIT',{badarg,_}} = (catch ets:match_spec_run([1], B)), 256: ok. 257: 258: 259: 260: trace_control_word(doc) -> 261: ["Test the erlang:system_info(trace_control_word) and ", 262: "erlang:system_flag(trace_control_word, Value) BIFs, ", 263: "as well as the get_tcw/0 and set_tcw/1 PAM instructions"]; 264: trace_control_word(suite) -> []; 265: trace_control_word(Config) when is_list(Config) -> 266: ?line 32 = Bits = tcw_bits(), 267: ?line High = 1 bsl (Bits - 1), 268: ?line erlang:system_flag(trace_control_word, 17), 269: ?line tr(fun() -> ?MODULE:f1(a) end, 270: {?MODULE, f1, 1}, 271: [{'_',[{'=:=', {get_tcw}, 17}],[]}], 272: [{call, {?MODULE, f1, [a]}}]), 273: ?line tr(fun() -> ?MODULE:f1(a) end, 274: {?MODULE, f1, 1}, 275: [{'_',[{'=:=', {get_tcw}, 18}],[]}], 276: []), 277: ?line erlang:system_flag(trace_control_word, High), 278: ?line tr(fun() -> ?MODULE:f1(a) end, 279: {?MODULE, f1, 1}, 280: [{'_',[{'=:=', {get_tcw}, High}],[]}], 281: [{call, {?MODULE, f1, [a]}}]), 282: ?line erlang:system_flag(trace_control_word, 0), 283: ?line tr(fun() -> 284: ?MODULE:f1(a), 285: ?MODULE:f1(start), 286: ?MODULE:f1(b), 287: ?MODULE:f1(c), 288: ?MODULE:f1(high), 289: ?MODULE:f1(d), 290: ?MODULE:f1(stop), 291: ?MODULE:f1(e) 292: end, 293: {?MODULE, f1, 1}, 294: [{[start], 295: [], 296: [{message, {set_tcw, 17}}]}, 297: {[stop], 298: [], 299: [{message, {set_tcw, 0}}]}, 300: {[high], 301: [], 302: [{message, {set_tcw, High}}]}, 303: {['_'], 304: [{'>', {get_tcw}, 0}], 305: [{set_tcw, {'+', 1, {get_tcw}}}, {message, {get_tcw}}] }], 306: [{call, {?MODULE, f1, [start]}, 0}, 307: {call, {?MODULE, f1, [b]}, 18}, 308: {call, {?MODULE, f1, [c]}, 19}, 309: {call, {?MODULE, f1, [high]}, 19}, 310: {call, {?MODULE, f1, [d]}, High + 1}, 311: {call, {?MODULE, f1, [stop]}, High + 1}]), 312: ?line 0 = erlang:system_info(trace_control_word), 313: ok. 314: 315: tcw_bits() -> 316: ?line tcw_bits(erlang:system_flag(trace_control_word, 0), 0, 0). 317: 318: tcw_bits(Save, Prev, Bits) -> 319: ?line Curr = 1 bsl Bits, 320: ?line case catch erlang:system_flag(trace_control_word, Curr) of 321: {'EXIT' , {badarg, _}} -> 322: ?line Prev = erlang:system_flag(trace_control_word, Save), 323: Bits; 324: Prev -> 325: ?line Curr = erlang:system_info(trace_control_word), 326: tcw_bits(Save, Curr, Bits+1) 327: end. 328: 329: 330: 331: silent(doc) -> 332: ["Test the erlang:trace(_, _, [silent]) flag ", 333: "as well as the silent/0 PAM instruction"]; 334: silent(suite) -> []; 335: silent(Config) when is_list(Config) -> 336: %% Global call trace 337: ?line tr(fun() -> 338: ?MODULE:f1(a), % No trace - not active 339: ?MODULE:f1(miss), % No trace - no activation 340: ?MODULE:f1(b), % No trace - still not active 341: ?MODULE:f1(start), % Trace - activation 342: ?MODULE:f1(c), % Trace - active 343: f1(d), % No trace - local call 344: ?MODULE:f1(miss), % Trace - no inactivation 345: ?MODULE:f1(e), % Trace - still active 346: ?MODULE:f1(stop), % No trace - inactivation 347: ?MODULE:f1(f) % No trace - not active 348: end, 349: {?MODULE, f1, 1}, 350: [call, silent], 351: [{[start], 352: [], 353: [{silent, false}, {message, start}]}, 354: {[stop], 355: [], 356: [{silent, true}, {message, stop}]}, 357: {[miss], 358: [], 359: [{silent, neither_true_nor_false}, {message, miss}]}, 360: {['$1'], 361: [], 362: [{message, '$1'}] }], 363: [global], 364: [{call, {?MODULE, f1, [start]}, start}, 365: {call, {?MODULE, f1, [c]}, c}, 366: {call, {?MODULE, f1, [miss]}, miss}, 367: {call, {?MODULE, f1, [e]}, e} ]), 368: %% Local call trace 369: ?line tr(fun() -> 370: ?MODULE:f1(a), % No trace - not active 371: f1(b), % No trace - not active 372: ?MODULE:f1(start), % Trace - activation 373: ?MODULE:f1(c), % Trace - active 374: f1(d), % Trace - active 375: f1(stop), % No trace - inactivation 376: ?MODULE:f1(e), % No trace - not active 377: f1(f) % No trace - not active 378: end, 379: {?MODULE, f1, 1}, 380: [call, silent], 381: [{[start], 382: [], 383: [{silent, false}, {message, start}]}, 384: {[stop], 385: [], 386: [{silent, true}, {message, stop}]}, 387: {['$1'], 388: [], 389: [{message, '$1'}] }], 390: [local], 391: [{call, {?MODULE, f1, [start]}, start}, 392: {call, {?MODULE, f1, [c]}, c}, 393: {call, {?MODULE, f1, [d]}, d} ]), 394: ok. 395: 396: silent_no_ms(doc) -> 397: ["Test the erlang:trace(_, _, [silent]) flag without match specs"]; 398: silent_no_ms(suite) -> []; 399: silent_no_ms(Config) when is_list(Config) -> 400: %% Global call trace 401: %% 402: %% Trace f2/2 and erlang:integer_to_list/1 without match spec 403: %% and use match spec on f1/1 to control silent flag. 404: ?line tr( 405: fun () -> 406: ?MODULE:f1(a), 407: ?MODULE:f2(b, c), 408: _ = erlang:integer_to_list(id(1)), 409: ?MODULE:f3(d, e), 410: ?MODULE:f1(start), 411: ?MODULE:f2(f, g), 412: _ = erlang:integer_to_list(id(2)), 413: ?MODULE:f3(h, i), 414: ?MODULE:f1(stop), 415: ?MODULE:f2(j, k), 416: _ = erlang:integer_to_list(id(3)), 417: ?MODULE:f3(l, m) 418: end, 419: fun (Tracee) -> 420: ?line 1 = 421: erlang:trace(Tracee, true, 422: [call,silent,return_to]), 423: ?line 1 = 424: erlang:trace_pattern( 425: {?MODULE,f2,2}, 426: [], 427: [global]), 428: ?line 1 = 429: erlang:trace_pattern( 430: {erlang,integer_to_list,1}, 431: [], 432: [global]), 433: ?line 1 = 434: erlang:trace_pattern( 435: {?MODULE,f1,1}, 436: [{[start],[],[{silent,false}]}, 437: {[stop],[],[{silent,true}]}], 438: [global]), 439: %% 440: %% Expected: (no return_to for global call trace) 441: %% 442: ?line 443: [{trace,Tracee,call,{?MODULE,f1,[start]}}, 444: {trace,Tracee,call,{?MODULE,f2,[f,g]}}, 445: {trace,Tracee,call,{erlang,integer_to_list,[2]}}, 446: {trace,Tracee,call,{?MODULE,f2,[h,i]}}] 447: end), 448: %% Local call trace 449: %% 450: %% Trace f2/2 and erlang:integer_to_list/1 without match spec 451: %% and use match spec on f1/1 to control silent flag. 452: ?line tr( 453: fun () -> 454: ?MODULE:f1(a), 455: ?MODULE:f2(b, c), 456: _ = erlang:integer_to_list(id(1)), 457: ?MODULE:f3(d, e), 458: ?MODULE:f1(start), 459: ?MODULE:f2(f, g), 460: _ = erlang:integer_to_list(id(2)), 461: ?MODULE:f3(h, i), 462: ?MODULE:f1(stop), 463: ?MODULE:f2(j, k), 464: _ = erlang:integer_to_list(id(3)), 465: ?MODULE:f3(l, m) 466: end, 467: fun (Tracee) -> 468: ?line 1 = 469: erlang:trace(Tracee, true, 470: [call,silent,return_to]), 471: ?line 1 = 472: erlang:trace_pattern( 473: {?MODULE,f2,2}, 474: [], 475: [local]), 476: ?line 1 = 477: erlang:trace_pattern( 478: {erlang,integer_to_list,1}, 479: [], 480: [local]), 481: ?line 1 = 482: erlang:trace_pattern( 483: {?MODULE,f1,1}, 484: [{[start],[],[{silent,false}]}, 485: {[stop],[],[{silent,true}]}], 486: [local]), 487: %% 488: %% Expected: 489: %% 490: ?line 491: [{trace,Tracee,call,{?MODULE,f1,[start]}}, 492: {trace,Tracee,return_to, 493: {?MODULE,'-silent_no_ms/1-fun-2-',0}}, 494: {trace,Tracee,call,{?MODULE,f2,[f,g]}}, 495: {trace,Tracee,return_to, 496: {?MODULE,'-silent_no_ms/1-fun-2-',0}}, 497: {trace,Tracee,call,{erlang,integer_to_list,[2]}}, 498: {trace,Tracee,return_to, 499: {?MODULE,'-silent_no_ms/1-fun-2-',0}}, 500: {trace,Tracee,call,{?MODULE,f2,[h,i]}}, 501: {trace,Tracee,return_to,{?MODULE,f3,2}}] 502: end). 503: 504: silent_test(doc) -> 505: ["Test that match_spec_test does not activate silent"]; 506: silent_test(_Config) -> 507: {flags,[]} = erlang:trace_info(self(),flags), 508: erlang:match_spec_test([],[{'_',[],[{silent,true}]}],trace), 509: {flags,[]} = erlang:trace_info(self(),flags). 510: 511: 512: ms_trace2(doc) -> 513: ["Test the match spec functions {trace/2}"]; 514: ms_trace2(suite) -> []; 515: ms_trace2(Config) when is_list(Config) -> 516: Tracer = self(), 517: %% Meta trace init 518: %% 519: %% Trace global f1/1, local f2/2, global erlang:integer_to_list/1 520: %% without match spec. Use match spec functions 521: %% {trace/2} to control trace through fn/2,3. 522: ?line tr( 523: fun () -> 524: ?MODULE:f1(a), 525: ?MODULE:f2(b, c), 526: _ = erlang:integer_to_list(id(1)), 527: ?MODULE:f3(d, e), 528: fn([all], [call,return_to,{tracer,Tracer}]), 529: ?MODULE:f1(f), 530: f2(g, h), 531: f1(i), 532: _ = erlang:integer_to_list(id(2)), 533: ?MODULE:f3(j, k), 534: fn([call,return_to], []), 535: ?MODULE:f1(l), 536: ?MODULE:f2(m, n), 537: _ = erlang:integer_to_list(id(3)), 538: ?MODULE:f3(o, p) 539: end, 540: fun (Tracee) -> 541: ?line 1 = 542: erlang:trace(Tracee, false, [all]), 543: ?line 1 = 544: erlang:trace_pattern( 545: {?MODULE,f1,1}, 546: [], 547: [global]), 548: ?line 1 = 549: erlang:trace_pattern( 550: {?MODULE,f2,2}, 551: [], 552: [local]), 553: ?line 1 = 554: erlang:trace_pattern( 555: {erlang,integer_to_list,1}, 556: [], 557: [global]), 558: ?line 3 = 559: erlang:trace_pattern( 560: {?MODULE,fn,'_'}, 561: [{['$1','$2'],[], 562: [{trace,'$1','$2'},{message,ms_trace2}]}], 563: [meta]), 564: %% 565: %% Expected: (no return_to for global call trace) 566: %% 567: ?line Origin = {match_spec_SUITE,'-ms_trace2/1-fun-0-',1}, 568: ?line 569: [{trace_ts,Tracee,call, 570: {?MODULE,fn, 571: [[all],[call,return_to,{tracer,Tracer}]]}, 572: ms_trace2}, 573: {trace,Tracee,call,{?MODULE,f1,[f]}}, 574: {trace,Tracee,call,{?MODULE,f2,[g,h]}}, 575: {trace,Tracee,return_to,Origin}, 576: {trace,Tracee,call,{erlang,integer_to_list,[2]}}, 577: {trace,Tracee,call,{?MODULE,f2,[j,k]}}, 578: {trace,Tracee,return_to,{?MODULE,f3,2}}, 579: {trace_ts,Tracee,call, 580: {?MODULE,fn, 581: [[call,return_to],[]]}, 582: ms_trace2}] 583: end), 584: ok. 585: 586: 587: 588: ms_trace3(doc) -> 589: ["Test the match spec functions {trace/3}"]; 590: ms_trace3(suite) -> []; 591: ms_trace3(Config) when is_list(Config) -> 592: TraceeName = 'match_spec_SUITE:ms_trace3', 593: Tracer = self(), 594: %% Meta trace init 595: %% 596: %% Trace global f1/1, local f2/2, global erlang:integer_to_list/1 597: %% without match spec. Use match spec functions 598: %% {trace/2} to control trace through fn/2,3. 599: Tag = make_ref(), 600: Controller = 601: spawn_link( 602: fun () -> 603: receive 604: {Tracee,Tag,start} -> 605: fn(TraceeName, [all], 606: [call,return_to,send,'receive', 607: {tracer,Tracer}]), 608: Tracee ! {self(),Tag,started}, 609: receive {Tracee,Tag,stop_1} -> ok end, 610: fn(Tracee, [call,return_to], []), 611: Tracee ! {self(),Tag,stopped_1}, 612: receive {Tracee,Tag,stop_2} -> ok end, 613: fn(Tracee, [all], []), 614: Tracee ! {self(),Tag,stopped_2} 615: end 616: end), 617: ?line tr( 618: fun () -> %% Action 619: register(TraceeName, self()), 620: ?MODULE:f1(a), 621: ?MODULE:f2(b, c), 622: _ = erlang:integer_to_list(id(1)), 623: ?MODULE:f3(d, e), 624: Controller ! {self(),Tag,start}, 625: receive {Controller,Tag,started} -> ok end, 626: ?MODULE:f1(f), 627: f2(g, h), 628: f1(i), 629: _ = erlang:integer_to_list(id(2)), 630: ?MODULE:f3(j, k), 631: Controller ! {self(),Tag,stop_1}, 632: receive {Controller,Tag,stopped_1} -> ok end, 633: ?MODULE:f1(l), 634: ?MODULE:f2(m, n), 635: _ = erlang:integer_to_list(id(3)), 636: ?MODULE:f3(o, p), 637: Controller ! {self(),Tag,stop_2}, 638: receive {Controller,Tag,stopped_2} -> ok end, 639: ?MODULE:f1(q), 640: ?MODULE:f2(r, s), 641: _ = erlang:integer_to_list(id(4)), 642: ?MODULE:f3(t, u) 643: end, 644: 645: fun (Tracee) -> %% Startup 646: ?line 1 = 647: erlang:trace(Tracee, false, [all]), 648: ?line 1 = 649: erlang:trace_pattern( 650: {?MODULE,f1,1}, 651: [], 652: [global]), 653: ?line 1 = 654: erlang:trace_pattern( 655: {?MODULE,f2,2}, 656: [], 657: [local]), 658: ?line 1 = 659: erlang:trace_pattern( 660: {erlang,integer_to_list,1}, 661: [], 662: [global]), 663: ?line 3 = 664: erlang:trace_pattern( 665: {?MODULE,fn,'_'}, 666: [{['$1','$2','$3'],[], 667: [{trace,'$1','$2','$3'},{message,Tag}]}], 668: [meta]), 669: %% 670: %% Expected: (no return_to for global call trace) 671: %% 672: ?line Origin = {match_spec_SUITE,'-ms_trace3/1-fun-1-',2}, 673: ?line 674: [{trace_ts,Controller,call, 675: {?MODULE,fn,[TraceeName,[all], 676: [call,return_to,send,'receive', 677: {tracer,Tracer}]]}, 678: Tag}, 679: {trace,Tracee,'receive',{Controller,Tag,started}}, 680: {trace,Tracee,call,{?MODULE,f1,[f]}}, 681: {trace,Tracee,call,{?MODULE,f2,[g,h]}}, 682: {trace,Tracee,return_to,Origin}, 683: {trace,Tracee,call,{erlang,integer_to_list,[2]}}, 684: {trace,Tracee,call,{?MODULE,f2,[j,k]}}, 685: {trace,Tracee,return_to,{?MODULE,f3,2}}, 686: {trace,Tracee,send,{Tracee,Tag,stop_1},Controller}, 687: {trace_ts,Controller,call, 688: {?MODULE,fn,[Tracee,[call,return_to],[]]}, 689: Tag}, 690: {trace_ts,Controller,call, 691: {?MODULE,fn,[Tracee,[all],[]]}, 692: Tag}] 693: end), 694: ok. 695: 696: 697: 698: destructive_in_test_bif(doc) -> 699: ["Test that destructive operations in test bif does not really happen"]; 700: destructive_in_test_bif(suite) -> []; 701: destructive_in_test_bif(Config) when is_list(Config) -> 702: ?line {ok,OldToken,_,_} = erlang:match_spec_test 703: ([], 704: [{'_',[],[{message,{get_seq_token}}]}],trace), 705: ?line {ok,_,_,_} = erlang:match_spec_test 706: ([], 707: [{'_',[],[{message,{set_seq_token, label, 1}}]}], 708: trace), 709: ?line {ok,OldToken,_,_} = erlang:match_spec_test 710: ([], 711: [{'_',[],[{message,{get_seq_token}}]}],trace), 712: ?line {ok, OldTCW,_,_} = erlang:match_spec_test 713: ([],[{'_',[],[{message,{get_tcw}}]}],trace), 714: ?line {ok,OldTCW,_,_} = erlang:match_spec_test 715: ([], 716: [{'_',[],[{message,{set_tcw, OldTCW+1}}]}], 717: trace), 718: ?line {ok, OldTCW,_,_} = erlang:match_spec_test 719: ([],[{'_',[],[{message,{get_tcw}}]}],trace), 720: ok. 721: 722: boxed_and_small(doc) -> 723: ["Test that the comparision between boxed and small does not crash emulator"]; 724: boxed_and_small(suite) -> []; 725: boxed_and_small(Config) when is_list(Config) -> 726: ?line {ok, Node} = start_node(match_spec_suite_other), 727: ?line ok = rpc:call(Node,?MODULE,do_boxed_and_small,[]), 728: ?line stop_node(Node), 729: ok. 730: 731: do_boxed_and_small() -> 732: {ok, false, _, _} = erlang:match_spec_test({0,3},[{{1.47,'_'},[],['$_']}],table), 733: {ok, false, _, _} = erlang:match_spec_test({0,3},[{{12345678901234567890,'_'},[],['$_']}],table), 734: {ok, false, _, _} = erlang:match_spec_test({0,3},[{{<<1,2,3,4>>,'_'},[],['$_']}],table), 735: {ok, false, _, _} = erlang:match_spec_test({0,3},[{{make_ref(),'_'},[],['$_']}],table), 736: ok. 737: 738: faulty_seq_trace(doc) -> 739: ["Test that faulty seq_trace_call does not crash emulator"]; 740: faulty_seq_trace(suite) -> []; 741: faulty_seq_trace(Config) when is_list(Config) -> 742: ?line {ok, Node} = start_node(match_spec_suite_other), 743: ?line ok = rpc:call(Node,?MODULE,do_faulty_seq_trace,[]), 744: ?line stop_node(Node), 745: ok. 746: 747: do_faulty_seq_trace() -> 748: {ok,'EXIT',_,_} = erlang:match_spec_test([],[{'_',[],[{message,{set_seq_token,yxa,true}}]}],trace), 749: ok. 750: 751: errchk(Pat) -> 752: case catch erlang:trace_pattern({?MODULE, f2, 2}, Pat) of 753: {'EXIT', {badarg, _}} -> 754: ok; 755: Other -> 756: test_server:fail({noerror, Other}) 757: end. 758: 759: unary_minus(suite) -> 760: []; 761: unary_minus(doc) -> 762: ["Checks that unary minus works"]; 763: unary_minus(Config) when is_list(Config) -> 764: ?line {ok,true,[],[]} = erlang:match_spec_test 765: (5, 766: [{'$1', 767: [{'<',{'-','$1'},-4}], 768: [true]}], 769: table), 770: ?line {ok,false,[],[]} = erlang:match_spec_test 771: (5, 772: [{'$1', 773: [{'<',{'-','$1'},-6}], 774: [true]}], 775: table), 776: ?line {ok,true,[],[]} = erlang:match_spec_test 777: (5, 778: [{'$1', 779: [{'=:=',{'-','$1',2},3}], 780: [true]}], 781: table), 782: ?line {ok,false,[],[]} = erlang:match_spec_test 783: (hej, 784: [{'$1', 785: [{'=/=',{'-','$1'},0}], 786: [true]}], 787: table), 788: ok. 789: unary_plus(suite) -> 790: []; 791: unary_plus(doc) -> 792: ["Checks that unary plus works"]; 793: unary_plus(Config) when is_list(Config) -> 794: ?line {ok,true,[],[]} = erlang:match_spec_test 795: (5, 796: [{'$1', 797: [{'<',{'+','$1'},6}], 798: [true]}], 799: table), 800: ?line {ok,false,[],[]} = erlang:match_spec_test 801: (5, 802: [{'$1', 803: [{'<',{'+','$1'},4}], 804: [true]}], 805: table), 806: ?line {ok,true,[],[]} = erlang:match_spec_test 807: (5, 808: [{'$1', 809: [{'=:=',{'+','$1',2},7}], 810: [true]}], 811: table), 812: ?line {ok,false,[],[]} = erlang:match_spec_test 813: (hej, 814: [{'$1', 815: [{'=/=',{'+','$1'},0}], 816: [true]}], 817: table), 818: ok. 819: 820: 821: 822: 823: guard_exceptions(suite) -> 824: []; 825: guard_exceptions(doc) -> 826: ["Checks that exceptions in guards are handled correctly"]; 827: guard_exceptions(Config) when is_list(Config) -> 828: ?line {ok,false,[],[]} = erlang:match_spec_test 829: (5, 830: [{'$1', 831: [{'or',{is_integer,'$1'},{'or','$1','$1'}}], 832: [true]}], 833: table), 834: ?line {ok,true,[],[]} = erlang:match_spec_test 835: (5, 836: [{'$1', 837: [{'orelse',{is_integer,'$1'}, 838: {'or','$1','$1'}}], 839: [true]}], 840: table), 841: ?line {ok,false,[],[]} = erlang:match_spec_test 842: (5, 843: [{'$1', 844: [{'orelse',{'or','$1',true}, 845: {is_integer,'$1'}}], 846: [true]}], 847: table), 848: ?line {ok,false,[],[]} = erlang:match_spec_test 849: (5, 850: [{'$1', 851: [{'or',{is_integer,'$1'}, 852: {'orelse','$1',true}}], 853: [true]}], 854: table), 855: ?line {ok,true,[],[]} = erlang:match_spec_test 856: (5, 857: [{'$1', 858: [{'or',{is_integer,'$1'}, 859: {'orelse',true,'$1'}}], 860: [true]}], 861: table), 862: ?line {ok,true,[],[]} = erlang:match_spec_test 863: (5, 864: [{'$1', 865: [{'or',{is_integer,'$1'}, 866: {'andalso',false,'$1'}}], 867: [true]}], 868: table), 869: ?line {ok,false,[],[]} = erlang:match_spec_test 870: (5, 871: [{'$1', 872: [{'or',{is_integer,'$1'}, 873: {'andalso','$1',false}}], 874: [true]}], 875: table), 876: 877: ?line {ok,false,[],[]} = erlang:match_spec_test 878: (5, 879: [{'$1', 880: [{'or',{is_integer,'$1'}, 881: {'andalso','$1',false}}], 882: [true]}], 883: table), 884: 885: ok. 886: 887: fpe(suite) -> 888: []; 889: fpe(doc) -> 890: ["Checks floating point exceptions in match-specs"]; 891: fpe(Config) when is_list(Config) -> 892: MS = [{{'$1'},[],[{'/','$1',0}]}], 893: case catch (['EXIT','EXIT'] = 894: ets:match_spec_run([{1},{2}],ets:match_spec_compile(MS))) of 895: {'EXIT',_} -> test_server:fail({error, 896: "Floating point exceptions faulty"}); 897: _ -> ok 898: end. 899: 900: moving_labels(Config) when is_list(Config) -> 901: %% Force an andalso/orelse construction to be moved by placing it 902: %% in a tuple followed by a constant term. Labels should still 903: %% point at their correct target. 904: %% 905: Ms = [{{'$1','$2'},[],[{{ok,{'andalso','$1','$2'},[1,2,3]}}]}], 906: ?line {ok,{ok,false,[1,2,3]},[],[]} = 907: erlang:match_spec_test({true,false}, Ms, table), 908: 909: Ms2 = [{{'$1','$2'},[],[{{ok,{'orelse','$1','$2'},[1,2,3]}}]}], 910: ?line {ok,{ok,true,[1,2,3]},[],[]} = 911: erlang:match_spec_test({true,false}, Ms2, table), 912: 913: ok. 914: 915: tr(Fun, MFA, Pat, Expected) -> 916: tr(Fun, MFA, [call], Pat, [global], Expected). 917: 918: tr(Fun, MFA, TraceFlags, Pat, PatFlags, Expected0) -> 919: tr(Fun, 920: fun(P) -> 921: erlang:trace(P, true, TraceFlags), 922: erlang:trace_pattern(MFA, Pat, PatFlags), 923: lists:map( 924: fun(X) -> 925: list_to_tuple([trace, P | tuple_to_list(X)]) 926: end, 927: Expected0) 928: end). 929: 930: tr(RunFun, ControlFun) -> 931: P = spawn(?MODULE, runner, [self(), RunFun]), 932: collect(P, ControlFun(P)). 933: 934: collect(P, TMs) -> 935: start_collect(P), 936: collect(TMs), 937: stop_collect(P). 938: 939: collect([]) -> 940: receive 941: M -> 942: ?t:format("Got unexpected: ~p~n", [M]), 943: flush({got_unexpected,M}) 944: after 17 -> 945: ok 946: end; 947: collect([TM | TMs]) -> 948: ?t:format( "Expecting: ~p~n", [TM]), 949: receive 950: M -> 951: case if element(1, M) == trace_ts -> 952: list_to_tuple(lists:reverse( 953: tl(lists:reverse(tuple_to_list(M))))); 954: true -> M 955: end of 956: TM -> 957: ?t:format("Got: ~p~n", [M]), 958: collect(TMs); 959: _ -> 960: ?t:format("Got unexpected: ~p~n", [M]), 961: flush({got_unexpected,M}) 962: end 963: end. 964: 965: flush(Reason) -> 966: receive 967: M -> 968: ?t:format("In queue: ~p~n", [M]), 969: flush(Reason) 970: after 17 -> 971: ?t:fail(Reason) 972: end. 973: 974: start_collect(P) -> 975: P ! {go, self()}. 976: 977: stop_collect(P) -> 978: stop_collect(P, done). 979: stop_collect(P, Order) -> 980: P ! {Order, self()}, 981: receive 982: {gone, P} -> 983: ok 984: end. 985: 986: 987: runner(Collector, Fun) -> 988: receive 989: {go, Collector} -> 990: go 991: end, 992: Fun(), 993: receive 994: {done, Collector} -> 995: Collector ! {gone, self()} 996: end. 997: 998: loop_runner(Collector, Fun, Laps) -> 999: receive 1000: {go, Collector} -> 1001: go 1002: end, 1003: loop_runner_cont(Collector, Fun, 0, Laps). 1004: 1005: loop_runner_cont(_Collector, _Fun, Laps, Laps) -> 1006: receive 1007: {done, Collector} -> 1008: io:format("loop_runner ~p exit after ~p laps\n", [self(), Laps]), 1009: Collector ! {gone, self()} 1010: end; 1011: loop_runner_cont(Collector, Fun, N, Laps) -> 1012: Fun(), 1013: receive 1014: {abort, Collector} -> 1015: io:format("loop_runner ~p aborted after ~p of ~p laps\n", [self(), N+1, Laps]), 1016: Collector ! {gone, self()} 1017: after 0 -> 1018: loop_runner_cont(Collector, Fun, N+1, Laps) 1019: end. 1020: 1021: 1022: f1(X) -> 1023: {X}. 1024: 1025: f2(X, Y) -> 1026: {X, Y}. 1027: 1028: f3(X,Y) -> 1029: ?MODULE:f2(X,Y), 1030: ok. 1031: 1032: fn(X) -> 1033: [X]. 1034: fn(X, Y) -> 1035: [X, Y]. 1036: fn(X, Y, Z) -> 1037: [X, Y, Z]. 1038: 1039: id(X) -> 1040: X. 1041: 1042: start_node(Name) -> 1043: Pa = filename:dirname(code:which(?MODULE)), 1044: Cookie = atom_to_list(erlang:get_cookie()), 1045: test_server:start_node(Name, slave, 1046: [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]). 1047: 1048: stop_node(Node) -> 1049: test_server:stop_node(Node).