1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2007-2011. 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(sensitive_SUITE). 21: 22: -include_lib("test_server/include/test_server.hrl"). 23: 24: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 25: init_per_group/2,end_per_group/2, 26: init_per_testcase/2,end_per_testcase/2, 27: stickiness/1,send_trace/1,recv_trace/1,proc_trace/1,call_trace/1, 28: meta_trace/1,running_trace/1,gc_trace/1,seq_trace/1, 29: t_process_info/1,t_process_display/1,save_calls/1]). 30: 31: -export([remote_process_display/0,an_exported_function/1]). 32: 33: -import(lists, [keysearch/3,foreach/2,sort/1]). 34: 35: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 36: Dog = ?t:timetrap(?t:minutes(5)), 37: [{watchdog,Dog}|Config]. 38: 39: end_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 40: Dog = ?config(watchdog, Config), 41: ?t:timetrap_cancel(Dog). 42: 43: suite() -> [{ct_hooks,[ts_install_cth]}]. 44: 45: all() -> 46: [stickiness, send_trace, recv_trace, proc_trace, 47: call_trace, meta_trace, running_trace, gc_trace, 48: seq_trace, t_process_info, t_process_display, 49: save_calls]. 50: 51: groups() -> 52: []. 53: 54: init_per_suite(Config) -> 55: Config. 56: 57: end_per_suite(_Config) -> 58: ok. 59: 60: init_per_group(_GroupName, Config) -> 61: Config. 62: 63: end_per_group(_GroupName, Config) -> 64: Config. 65: 66: 67: stickiness(Config) when is_list(Config) -> 68: ?line {Tracer,Mref} = spawn_monitor(fun() -> 69: receive after infinity -> ok end 70: end), 71: ?line false = process_flag(sensitive, true), 72: put(foo, bar), 73: 74: Flags = sort([send,'receive',procs,call,running,garbage_collection, 75: set_on_spawn,set_on_first_spawn,set_on_link,set_on_first_link]), 76: ?line foreach(fun(F) -> 77: 1 = erlang:trace(self(), true, [F,{tracer,Tracer}]) 78: end, Flags), 79: ?line foreach(fun(F) -> 80: 1 = erlang:trace(self(), false, [F,{tracer,Tracer}]) 81: end, Flags), 82: ?line 1 = erlang:trace(self(), true, [{tracer,Tracer}|Flags]), 83: ?line 1 = erlang:trace(self(), false, [{tracer,Tracer}|Flags]), 84: 85: ?line {messages,[]} = process_info(Tracer, messages), 86: exit(Tracer, kill), 87: receive {'DOWN',Mref,_,_,_} -> ok end, 88: 89: case process_info(self(), dictionary) of 90: {dictionary,[]} -> ok; 91: {dictionary,_} -> ?line ?t:fail(sensitive_flag_cleared) 92: end, 93: 94: NewTracer = spawn_link(fun() -> receive after infinity -> ok end end), 95: ?line 1 = erlang:trace(self(), true, [{tracer,NewTracer}|Flags]), 96: ?line Flags = sort(element(2, erlang:trace_info(self(), flags))), 97: ?line {tracer,NewTracer} = erlang:trace_info(self(), tracer), 98: 99: %% Process still sensitive. Tracer should disappear when we clear 100: %% all trace flags. 101: ?line 1 = erlang:trace(self(), false, [{tracer,NewTracer}|Flags]), 102: ?line {tracer,[]} = erlang:trace_info(self(), tracer), 103: 104: ?line unlink(NewTracer), exit(NewTracer, kill), 105: ok. 106: 107: send_trace(Config) when is_list(Config) -> 108: ?line {Dead,Mref} = spawn_monitor(fun() -> ok end), 109: receive {'DOWN',Mref,_,_,_} -> ok end, 110: ?line Tracer = spawn_link(fun() -> receive after infinity -> ok end end), 111: ?line Sink = spawn_link(fun() -> receive after infinity -> ok end end), 112: Self = self(), 113: 114: ?line 1 = erlang:trace(self(), true, [send,{tracer,Tracer}]), 115: ?line Dead ! before, 116: ?line Sink ! before, 117: ?line false = process_flag(sensitive, true), 118: ?line Sink ! {blurf,lists:seq(1, 50)}, 119: ?line true = process_flag(sensitive, true), 120: ?line Sink ! lists:seq(1, 100), 121: ?line Dead ! forget_me, 122: ?line true = process_flag(sensitive, false), 123: ?line Sink ! after1, 124: ?line false = process_flag(sensitive, false), 125: ?line Sink ! after2, 126: ?line Dead ! after2, 127: ?line wait_trace(Self), 128: 129: ?line {messages,Messages} = process_info(Tracer, messages), 130: ?line [{trace,Self,send_to_non_existing_process,before,Dead}, 131: {trace,Self,send,before,Sink}, 132: {trace,Self,send,after1,Sink}, 133: {trace,Self,send,after2,Sink}, 134: {trace,Self,send_to_non_existing_process,after2,Dead}] = Messages, 135: 136: ?line unlink(Tracer), exit(Tracer, kill), 137: ?line unlink(Sink), exit(Sink, kill), 138: ok. 139: 140: recv_trace(Config) when is_list(Config) -> 141: Parent = self(), 142: ?line Tracer = spawn_link(fun() -> receive after infinity -> ok end end), 143: ?line Sender = spawn_link(fun() -> recv_trace_sender(Parent) end), 144: 145: ?line 1 = erlang:trace(self(), true, ['receive',{tracer,Tracer}]), 146: 147: Sender ! 1, 148: receive a -> wait_trace(Sender) end, 149: 150: ?line false = process_flag(sensitive, true), 151: 152: Sender ! 2, 153: receive {b,[x,y,z]} -> wait_trace(Sender) end, 154: 155: ?line true = process_flag(sensitive, false), 156: 157: Sender ! 3, 158: receive c -> wait_trace(Sender) end, 159: 160: ?line {messages,Messages} = process_info(Tracer, messages), 161: [{trace,Parent,'receive',a}, 162: {trace,Parent,'receive',{trace_delivered,_,_}}, 163: {trace,Parent,'receive',c}|_] = Messages, 164: 165: ?line unlink(Tracer), exit(Tracer, kill), 166: ?line unlink(Sender), exit(Sender, kill), 167: ok. 168: 169: recv_trace_sender(Pid) -> 170: receive 171: 1 -> Pid ! a; 172: 2 -> Pid ! {b,[x,y,z]}; 173: 3 -> Pid ! c 174: end, 175: recv_trace_sender(Pid). 176: 177: proc_trace(Config) when is_list(Config) -> 178: Self = self(), 179: ?line Tracer = spawn_link(fun() -> receive after infinity -> ok end end), 180: 181: ?line 1 = erlang:trace(self(), true, [procs,{tracer,Tracer}]), 182: ?line false = process_flag(sensitive, true), 183: 184: spawn(fun() -> ok end), 185: ?line register(nisse, self()), 186: ?line unregister(nisse), 187: ?line link(Tracer), 188: ?line unlink(Tracer), 189: ?line Linker0 = spawn_link(fun() -> ok end), 190: Mref0 = erlang:monitor(process, Linker0), 191: 192: ?line {_,Mref} = spawn_monitor(fun() -> link(Self), unlink(Self) end), 193: 194: receive {'DOWN',Mref0,_,_,_} -> ok end, 195: 196: receive {'DOWN',Mref,_,_,_} -> ok end, 197: 198: ?line true = process_flag(sensitive, false), 199: 200: Dead = spawn(fun() -> ok end), 201: ?line register(arne, self()), 202: ?line unregister(arne), 203: ?line {Linker,Mref2} = spawn_monitor(fun() -> link(Self), unlink(Self) end), 204: receive {'DOWN',Mref2,_,_,_} -> ok end, 205: ?line Last = spawn_link(fun() -> ok end), 206: receive after 10 -> ok end, 207: ?line wait_trace(all), 208: ?line {messages,Messages} = process_info(Tracer, messages), 209: [{trace,Self,spawn,Dead,{erlang,apply,_}}, 210: {trace,Self,register,arne}, 211: {trace,Self,unregister,arne}, 212: {trace,Self,spawn,Linker,_}, 213: {trace,Self,getting_linked,Linker}, 214: {trace,Self,getting_unlinked,Linker}, 215: {trace,Self,spawn,Last,_}, 216: {trace,Self,link,Last}, 217: {trace,Self,getting_unlinked,Last}] = Messages, 218: 219: ?line unlink(Tracer), exit(Tracer, kill), 220: ok. 221: 222: call_trace(Config) when is_list(Config) -> 223: Self = self(), 224: ?line Tracer = spawn_link(fun() -> receive after infinity -> ok end end), 225: 226: ?line 1 = erlang:trace(self(), true, [call,{tracer,Tracer}]), 227: ?line 1 = erlang:trace_pattern({?MODULE,an_exported_function,1}, 228: true, [global]), 229: ?line 1 = erlang:trace_pattern({erlang,list_to_binary,1}, true, [global]), 230: ?line 1 = erlang:trace_pattern({erlang,binary_to_list,1}, true, [local]), 231: ?line Local = erlang:trace_pattern({?MODULE,'_','_'}, true, [local]), 232: 233: ?line false = process_flag(sensitive, true), 234: ?line {ok,42} = a_local_function(42), 235: ?line 7 = an_exported_function(6), 236: ?line <<7,8,9,10>> = list_to_binary(id([7,8,9,10])), 237: ?line [42,43] = binary_to_list(id(<<42,43>>)), 238: ?line true = process_flag(sensitive, false), 239: 240: ?line {ok,{a,b}} = a_local_function({a,b}), 241: ?line 1 = an_exported_function(0), 242: ?line <<1,2,3>> = list_to_binary(id([1,2,3])), 243: ?line [42,43,44] = binary_to_list(id(<<42,43,44>>)), 244: 245: ?line wait_trace(Self), 246: 247: ?line {messages,Messages} = process_info(Tracer, messages), 248: ?line [{trace,Self,call,{?MODULE,a_local_function,[{a,b}]}}, 249: {trace,Self,call,{?MODULE,an_exported_function,[0]}}, 250: {trace,Self,call,{?MODULE,id,[_]}}, 251: {trace,Self,call,{erlang,list_to_binary,[[1,2,3]]}}, 252: {trace,Self,call,{sensitive_SUITE,id,[<<42,43,44>>]}}, 253: {trace,Self,call,{erlang,binary_to_list,[<<42,43,44>>]}}, 254: {trace,Self,call,{?MODULE,wait_trace,[Self]}}] = Messages, 255: 256: ?line Local = erlang:trace_pattern({?MODULE,'_','_'}, false, [local]), 257: ?line erlang:trace_pattern({erlang,'_','_'}, false, [local]), 258: ?line erlang:trace_pattern({'_','_','_'}, false, [global]), 259: 260: ?line unlink(Tracer), exit(Tracer, kill), 261: ok. 262: 263: meta_trace(Config) when is_list(Config) -> 264: Self = self(), 265: ?line Tracer = spawn_link(fun() -> receive after infinity -> ok end end), 266: 267: ?line Local = erlang:trace_pattern({?MODULE,'_','_'}, true, [{meta,Tracer}]), 268: ?line 1 = erlang:trace_pattern({erlang,list_to_binary,1}, true, [{meta,Tracer}]), 269: 270: ?line false = process_flag(sensitive, true), 271: ?line {ok,blurf} = a_local_function(blurf), 272: ?line 100 = an_exported_function(99), 273: ?line <<8,9,10>> = list_to_binary(id([8,9,10])), 274: ?line true = process_flag(sensitive, false), 275: 276: ?line {ok,{x,y}} = a_local_function({x,y}), 277: ?line 1 = an_exported_function(0), 278: ?line <<10>> = list_to_binary(id([10])), 279: ?line wait_trace(Self), 280: 281: ?line Local = erlang:trace_pattern({?MODULE,'_','_'}, false, [meta]), 282: ?line 1 = erlang:trace_pattern({erlang,list_to_binary,1}, false, [meta]), 283: ?line a_local_function(0), 284: 285: ?line {messages,Messages} = process_info(Tracer, messages), 286: ?line [{trace_ts,Self,call,{?MODULE,a_local_function,[{x,y}]},{_,_,_}}, 287: {trace_ts,Self,call,{?MODULE,an_exported_function,[0]},{_,_,_}}, 288: {trace_ts,Self,call,{?MODULE,id,[_]},{_,_,_}}, 289: {trace_ts,Self,call,{erlang,list_to_binary,[[10]]},{_,_,_}}, 290: {trace_ts,Self,call,{?MODULE,wait_trace,[Self]},{_,_,_}}] = Messages, 291: 292: ?line unlink(Tracer), exit(Tracer, kill), 293: ok. 294: 295: a_local_function(A) -> 296: {ok,A}. 297: 298: an_exported_function(X) -> 299: X+1. 300: 301: running_trace(Config) when is_list(Config) -> 302: Self = self(), 303: ?line Tracer = spawn_link(fun() -> receive after infinity -> ok end end), 304: 305: ?line false = process_flag(sensitive, true), 306: ?line 1 = erlang:trace(Self, true, [running,{tracer,Tracer}]), 307: erlang:yield(), erlang:yield(), erlang:yield(), erlang:yield(), 308: erlang:yield(), erlang:yield(), erlang:yield(), erlang:yield(), 309: ?line true = process_flag(sensitive, false), 310: erlang:yield(), 311: ?line 1 = erlang:trace(Self, false, [running,{tracer,Tracer}]), 312: 313: ?line wait_trace(Self), 314: ?line {messages,Messages} = process_info(Tracer, messages), 315: ?line [{trace,Self,out,{sensitive_SUITE,running_trace,1}}, 316: {trace,Self,in,{sensitive_SUITE,running_trace,1}}] = Messages, 317: 318: ?line unlink(Tracer), exit(Tracer, kill), 319: ok. 320: 321: gc_trace(Config) when is_list(Config) -> 322: Self = self(), 323: ?line Tracer = spawn_link(fun() -> receive after infinity -> ok end end), 324: 325: ?line false = process_flag(sensitive, true), 326: ?line 1 = erlang:trace(Self, true, [garbage_collection,{tracer,Tracer}]), 327: erlang:garbage_collect(), erlang:garbage_collect(), 328: erlang:garbage_collect(), erlang:garbage_collect(), 329: erlang:garbage_collect(), erlang:garbage_collect(), 330: erlang:garbage_collect(), erlang:garbage_collect(), 331: ?line true = process_flag(sensitive, false), 332: erlang:garbage_collect(), 333: ?line 1 = erlang:trace(Self, false, [garbage_collection,{tracer,Tracer}]), 334: 335: ?line wait_trace(Self), 336: ?line {messages,Messages} = process_info(Tracer, messages), 337: ?line [{trace,Self,gc_start,_},{trace,Self,gc_end,_}] = Messages, 338: 339: ?line unlink(Tracer), exit(Tracer, kill), 340: ok. 341: 342: seq_trace(Config) when is_list(Config) -> 343: Self = self(), 344: ?line Tracer = spawn_link(fun() -> receive after infinity -> ok end end), 345: ?line seq_trace:set_system_tracer(Tracer), 346: 347: ?line false = process_flag(sensitive, true), 348: 349: ?line Echo = spawn_link(fun() -> 350: receive 351: {Pid,Message} -> 352: Pid ! {reply,Message} 353: end 354: end), 355: ?line Sender = spawn_link(fun() -> 356: seq_trace:set_token(label, 42), 357: seq_trace:set_token('receive', true), 358: seq_trace:set_token(send, true), 359: seq_trace:set_token(print, true), 360: seq_trace:print(42, "trace started"), 361: Self ! blurf 362: end), 363: seq_trace:set_token(label, 17), 364: seq_trace:set_token('receive', true), 365: seq_trace:set_token(send, true), 366: seq_trace:set_token(print, true), 367: seq_trace:print(17, "trace started"), 368: Echo ! {Self,hello}, 369: receive {reply,hello} -> ok end, 370: receive blurf -> ok end, 371: 372: ?line wait_trace(all), 373: 374: ?line {messages,Messages} = process_info(Tracer, messages), 375: ?line [{seq_trace,17,{'receive',{0,2},Self,Echo,{Self,hello}}}, 376: {seq_trace,17,{send,{2,3},Echo,Self,{reply,hello}}}] = 377: [M || {seq_trace,17,_}=M <- Messages], 378: 379: ?line [{seq_trace,42,{print,{0,1},Sender,[],"trace started"}}, 380: {seq_trace,42,{send,{0,2},Sender,Self,blurf}}] = 381: [M || {seq_trace,42,_}=M <- Messages], 382: 383: ?line unlink(Tracer), exit(Tracer, kill), 384: ?line unlink(Echo), exit(Echo, kill), 385: ?line unlink(Sender), exit(Sender, kill), 386: ok. 387: 388: t_process_info(Config) when is_list(Config) -> 389: Parent = self(), 390: ?line Pid = spawn_link(fun() -> 391: put(foo, bar), 392: false = process_flag(sensitive, true), 393: Parent ! go, 394: receive 395: revert -> 396: true = process_flag(sensitive, false), 397: Parent ! go_again, 398: receive never -> ok end 399: end end), 400: receive go -> ok end, 401: 402: ?line put(foo, bar), 403: ?line self() ! Pid ! {i,am,a,message}, 404: 405: ?line false = process_flag(sensitive, true), 406: ?line t_process_info_suppressed(self()), 407: ?line t_process_info_suppressed(Pid), 408: 409: ?line true = process_flag(sensitive, false), 410: Pid ! revert, 411: receive go_again -> ok end, 412: 413: ?line t_process_info_normal(self()), 414: ?line t_process_info_normal(Pid), 415: ok. 416: 417: t_process_info_suppressed(Pid) -> 418: [] = my_process_info(Pid, dictionary), 419: <<>> = my_process_info(Pid, backtrace), 420: [] = my_process_info(Pid, messages). 421: 422: t_process_info_normal(Pid) -> 423: {value,{foo,bar}} = keysearch(foo, 1, my_process_info(Pid, dictionary)), 424: case process_info(Pid, backtrace) of 425: {backtrace,Bin} when size(Bin) > 20 -> ok 426: end, 427: [{i,am,a,message}] = my_process_info(Pid, messages). 428: 429: my_process_info(Pid, Tag) -> 430: {Tag,Value} = process_info(Pid, Tag), 431: All = process_info(Pid), 432: case keysearch(Tag, 1, All) of 433: false -> Value; 434: {value,{Tag,Value}} -> Value 435: end. 436: 437: t_process_display(Config) when is_list(Config) -> 438: ?line Dir = filename:dirname(code:which(?MODULE)), 439: ?line Cmd = atom_to_list(lib:progname()) ++ " -noinput -pa " ++ Dir ++ 440: " -run " ++ ?MODULE_STRING ++ " remote_process_display", 441: ?line io:put_chars(Cmd), 442: ?line P = open_port({spawn,Cmd}, [in,stderr_to_stdout,eof]), 443: <<"done",_/binary>> = get_all(P), 444: ok. 445: 446: remote_process_display() -> 447: false = process_flag(sensitive, true), 448: erlang:process_display(self(), backtrace), 449: erlang:display(done), 450: receive after 10 -> ok end, 451: init:stop(). 452: 453: get_all(P) -> 454: get_all(P, []). 455: 456: get_all(P, Acc) -> 457: receive 458: {P,{data,S}} -> 459: get_all(P, [Acc|S]); 460: {P,eof} -> 461: iolist_to_binary(Acc) 462: end. 463: 464: save_calls(Config) when is_list(Config) -> 465: process_flag(save_calls, 10), 466: 467: false = process_flag(sensitive, true), 468: ?line {last_calls,LastCalls} = process_info(self(), last_calls), 469: ?line [{erlang,process_flag,2}] = LastCalls, 470: ?line [2,4,6] = lists:map(fun(E) -> 2*E end, [1,2,3]), 471: ?line {last_calls,LastCalls} = process_info(self(), last_calls), 472: ok. 473: 474: wait_trace(Pid) -> 475: Ref = erlang:trace_delivered(Pid), 476: receive 477: {trace_delivered,Pid,Ref} -> ok 478: end. 479: 480: id(I) -> I. 481: