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