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