%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%% Purpose : User interface to the Erlang debugger/interpreter.
-module(i).
-export([help/0,ia/1,ia/2,ia/3,ia/4,iaa/1,iaa/2,
ib/2,ib/3,ib/4,ibd/2,ibe/2,iba/3,ibc/3,ic/0,ii/1,ii/2,
il/0,im/0,ini/1,ini/2,inq/1,ip/0,ipb/0,ipb/1,iq/1,
ir/0,ir/1,ir/2,ir/3,iv/0,ist/1]).
-import(io, [format/1,format/2]).
-import(lists, [sort/1,foreach/2]).
iv() ->
Vsn = string:substr(filename:basename(code:lib_dir(debugger)), 10),
list_to_atom(Vsn).
%% -------------------------------------------
%% Start a new graphical monitor.
%% A monitor displays status for all processes
%% running interpreted modules.
%% -------------------------------------------
im() ->
case debugger:start() of
{ok, Pid} ->
Pid;
{error, {already_started, Pid}} ->
Pid
end.
%% -------------------------------------------
%% Add Module(s) as being interpreted.
%% The actual paths will be searched for the
%% corresponding source file(s) (Module.erl).
%% Module(s) can be given with absolute path.
%% -------------------------------------------
ii(Module) ->
int:i(Module).
ii(Module,_Options) ->
int:i(Module).
%% -------------------------------------------
%% Don't interpret module(s). The module will be
%% removed from the set of modules interpreted.
%% -------------------------------------------
iq(Module) ->
int:n(Module).
%% -------------------------------------------
%% The corresponding functions for distributed
%% erlang. The loading ... will be performed
%% at all nodes using the broadcast facility.
%% -------------------------------------------
ini(Module) ->
int:ni(Module).
ini(Module,_Options) ->
int:ni(Module).
inq(Module) ->
int:nn(Module).
%% -------------------------------------------
%% Add a new break point at Line in Module.
%% -------------------------------------------
ib(Module,Line) ->
int:break(Module,Line).
%% -------------------------------------------
%% Break at entrance of specified function.
%% Breaks is set at the first expression for
%% all function clauses.
%% -------------------------------------------
ib(Module,Function,Arity) ->
int:break_in(Module,Function,Arity).
%% -------------------------------------------
%% Break at entrance of specified function.
%% Breaks is set at the first expression for
%% all function clauses.
%% Associate the condition to the break.
%% -------------------------------------------
ib(Module,Function,Arity,Cond) ->
Breaks1 = int:all_breaks(Module),
ok = int:break_in(Module,Function,Arity),
Breaks2 = int:all_breaks(Module),
lists:foreach(fun({Mod,Line}) -> int:test_at_break(Mod,Line,Cond) end,
Breaks2--Breaks1).
%% -------------------------------------------
%% Make an existing break point inactive.
%% -------------------------------------------
ibd(Mod,Line) ->
int:disable_break(Mod,Line).
%% -------------------------------------------
%% Make an existing break point active.
%% -------------------------------------------
ibe(Mod,Line) ->
int:enable_break(Mod,Line).
%% -------------------------------------------
%% Set which status a break point shall have
%% after it has been triggered the next time.
%% Action is: enable, disable or delete.
%% -------------------------------------------
iba(Mod,Line,Action) ->
int:action_at_break(Mod,Line,Action).
%% -------------------------------------------
%% Add a conditional function to a break point.
%% The given function shall have arity 1 and
%% return either true or false.
%% The argument of the given function is the
%% current variable bindings of the process at
%% the place of the break point, the bindings
%% can be inspected using int:get_binding/2.
%% Fnk == {Module,Function}
%% Fnk == {Module,Function,ExtraArgs}
%% -------------------------------------------
ibc(Mod,Line,Fnk) ->
int:test_at_break(Mod,Line,Fnk).
%% -------------------------------------------
%% Delete break point.
%% -------------------------------------------
ir(Module,Line) ->
int:delete_break(Module,Line).
%% -------------------------------------------
%% Delete break at entrance of specified function.
%% -------------------------------------------
ir(Module,Function,Arity) ->
int:del_break_in(Module,Function,Arity).
%% -------------------------------------------
%% Delete all break points in module.
%% -------------------------------------------
ir(Module) ->
int:no_break(Module).
%% -------------------------------------------
%% Delete all break points (for all modules).
%% -------------------------------------------
ir() ->
int:no_break().
%% -------------------------------------------
%% Print all interpreted modules.
%% -------------------------------------------
il() ->
Mods = sort(int:interpreted()),
ilformat("Module","File"),
foreach(fun(Mod) -> ilformat(atom_to_list(Mod), get_file(Mod)) end, Mods).
get_file(Mod) ->
case int:file(Mod) of
{error,not_loaded} -> % Marked interpreted but not loaded
"not loaded";
File ->
File
end.
ilformat(A1, A2) ->
format("~-20s ~ts\n", [A1,A2]).
%% -------------------------------------------
%% Print all break points in modules.
%% -------------------------------------------
ipb() ->
Bps = lists:keysort(1,int:all_breaks()),
bhformat("Module","Line","Status","Action","Condition"),
pb_print(Bps).
ipb(Module) when is_atom(Module) ->
ipb1(Module);
ipb(Module) when is_list(Module) ->
ipb1(list_to_atom(Module)).
ipb1(Module) ->
Bps = lists:keysort(1,int:all_breaks(Module)),
bhformat("Module","Line","Status","Action","Condition"),
pb_print(Bps).
pb_print([{{Mod,Line},[Status,Action,_,null|_]}|Bps]) ->
bformat(Mod,Line,Status,Action,""),
pb_print(Bps);
pb_print([{{Mod,Line},[Status,Action,_,Cond|_]}|Bps]) ->
bformat(Mod,Line,Status,Action,
io_lib:format("~w",[Cond])),
pb_print(Bps);
pb_print(_) ->
ok.
bhformat(A1, A2, A3, A4, A5) ->
format("~-15s ~-9s ~-12s ~-12s ~-21s~n", [A1,A2,A3,A4,A5]).
bformat(A1, A2, A3, A4, A5) ->
format("~-15w ~-9w ~-12w ~-12w ~-21s~n", [A1,A2,A3,A4,A5]).
%% -------------------------------------------
%% Set the stack trace flag.
%% Flag can be all (true), no_tail or false.
%% -------------------------------------------
ist(Flag) ->
int:stack_trace(Flag),
true.
%% -------------------------------------------
%% Set the automatic attachment flag.
%% Flags can be init, break and exit.
%% iaa(Flag) or ia([Flag,Flag,...])
%% -------------------------------------------
iaa(Flag) ->
iaa(Flag,{dbg_wx_trace,start,[]}).
%% -------------------------------------------
%% Set the automatic attachment flag.
%% Flags can be init, break and exit.
%% Use given function to start up an attachment
%% window.
%% ia(Flag,Fnk) or ia([Flag,Flag,...],Fnk)
%% where Fnk == {M,F}
%% The given Fnk must have arity 3 or 4.
%% -------------------------------------------
iaa(Flag,Fnk) ->
int:auto_attach(Flag,Fnk),
true.
%% -------------------------------------------
%% Attach to process.
%% -------------------------------------------
ia(Pid) ->
ia(Pid,{dbg_wx_trace,start}).
%% -------------------------------------------
%% Attach to process.
%% X,Y,Z is combind to a process identity.
%% -------------------------------------------
ia(X,Y,Z) ->
ia(c:pid(X,Y,Z)).
%% -------------------------------------------
%% Attach to process.
%% Use Fnk == {M,F} as the attaching interface.
%% -------------------------------------------
ia(Pid,Fnk) ->
case lists:keymember(Pid, 1, int:snapshot()) of
false -> no_proc;
true -> int:attach(Pid,Fnk)
end.
ia(X,Y,Z,Fnk) ->
ia(c:pid(X,Y,Z),Fnk).
%% -------------------------------------------
%% Print status for all interpreted processes.
%% -------------------------------------------
ip() ->
Stats = int:snapshot(),
hformat("Pid","Initial Call","Status","Info"),
ip(Stats).
ip([{Pid,{M,F,A},Status,{}}|Stats]) ->
hformat(io_lib:format("~w",[Pid]),
io_lib:format("~w:~tw/~w",[M,F,length(A)]),
io_lib:format("~w",[Status]),
""),
ip(Stats);
ip([{Pid,{M,F,A},Status,Info}|Stats]) ->
hformat(io_lib:format("~w",[Pid]),
io_lib:format("~w:~tw/~w",[M,F,length(A)]),
io_lib:format("~w",[Status]),
io_lib:format("~w",[Info])),
ip(Stats);
ip([]) ->
ok.
hformat(A1, A2, A3, A4) ->
format("~-12s ~-21ts ~-9s ~-21s~n", [A1,A2,A3,A4]).
%% -------------------------------------------
%% Delete all terminated processes from the
%% interpreter.
%% -------------------------------------------
ic() ->
int:clear().
%% -------------------------------------------
%% Help printout
%% -------------------------------------------
help() ->
format("iv() -- print the current version of the interpreter~n"),
format("im() -- pop up a monitor window~n"),
format("ii(Mod) -- interpret Mod(s) (or AbsMod(s))~n"),
format("ii(Mod,Op) -- interpret Mod(s) (or AbsMod(s))~n"),
format(" use Op as options (same as for compile)~n"),
format("iq(Mod) -- do not interpret Mod(s)~n"),
format("ini(Mod) -- ii/1 at all Erlang nodes~n"),
format("ini(Mod,Op) -- ii/2 at all Erlang nodes~n"),
format("inq(Mod) -- iq at all Erlang nodes~n"),
format("ib(Mod,Line) -- set a break point at Line in Mod~n"),
format("ib(M,F,Arity)-- set a break point in M:F/Arity~n"),
format("ibd(Mod,Line)-- disable the break point at Line in Mod~n"),
format("ibe(Mod,Line)-- enable the break point at Line in Mod~n"),
format("iba(M,L,Action)-- set a new action at break~n"),
format("ibc(M,L,Action)-- set a new condition for break~n"),
format("ir(Mod,Line) -- remove the break point at Line in Mod~n"),
format("ir(M,F,Arity)-- remove the break point in M:F/Arity~n"),
format("ir(Mod) -- remove all break points in Mod~n"),
format("ir() -- remove all existing break points~n"),
format("il() -- list all interpreted modules~n"),
format("ip() -- print status of all interpreted processes~n"),
format("ic() -- remove all terminated interpreted processes~n"),
format("ipb() -- list all break points~n"),
format("ipb(Mod) -- list all break points in Mod~n"),
format("ia(Pid) -- attach to Pid~n"),
format("ia(X,Y,Z) -- attach to pid(X,Y,Z)~n"),
format("ia(Pid,Fun) -- use own Fun = {M,F} as attach application~n"),
format("ia(X,Y,Z,Fun)-- use own Fun = {M,F} as attach application~n"),
format("iaa([Flag]) -- set automatic attach to process~n"),
format(" Flag is init,break and exit~n"),
format("iaa([Fl],Fun)-- use own Fun = {M,F} as attach application~n"),
format("ist(Flag) -- set stack trace flag~n"),
format(" Flag is all (true),no_tail or false~n"),
ok.