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