diff options
Diffstat (limited to 'lib/debugger/src/dbg_ui_mon.erl')
-rw-r--r-- | lib/debugger/src/dbg_ui_mon.erl | 738 |
1 files changed, 0 insertions, 738 deletions
diff --git a/lib/debugger/src/dbg_ui_mon.erl b/lib/debugger/src/dbg_ui_mon.erl deleted file mode 100644 index 82fe210968..0000000000 --- a/lib/debugger/src/dbg_ui_mon.erl +++ /dev/null @@ -1,738 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% --module(dbg_ui_mon). - --include_lib("kernel/include/file.hrl"). - -%% External exports --export([start/2, stop/0]). - --define(TRACEWIN, ['Button Area', 'Evaluator Area', 'Bindings Area']). --define(BACKTRACE, 100). - --record(pinfo, {pid, % pid() - status % break | exit | idle | running | waiting - }). - --record(state, {mode, % local | global - starter, % bool() 'true' if int was started by me - - gs, % term() Graphics system id - win, % term() Monitor window data - focus, % undefined | #pinfo{} Process in focus - coords, % {X,Y} Mouse pointer position - - intdir, % string() Default dir - pinfos, % [#pinfo{}] Debugged processes - - tracewin, % [Area] Areas shown in trace window - backtrace, % integer() Number of call frames to fetch - - attach, % false | {Flags, Function} - - sfile, % default | string() Settings file - changed % boolean() Settings have been changed - }). - -%%==================================================================== -%% External exports -%%==================================================================== - -%%-------------------------------------------------------------------- -%% start(Mode, SFile) -> {ok, Pid} | {error, Reason} -%% Mode = local | global -%% SFile = string() | default Settings file -%% Pid = pid() -%% Reason = {already_started,Pid} | term() -%%-------------------------------------------------------------------- -start(Mode, SFile) -> - case whereis(?MODULE) of - undefined -> - CallingPid = self(), - Pid = spawn(fun () -> init(CallingPid, Mode, SFile) end), - receive - {initialization_complete, Pid} -> - {ok, Pid}; - Error -> - Error - end; - - Pid -> - {error, {already_started,Pid}} - end. - -%%-------------------------------------------------------------------- -%% stop() -> ok -%%-------------------------------------------------------------------- -stop() -> - case whereis(?MODULE) of - undefined -> - ok; - Pid -> - Flag = process_flag(trap_exit, true), - link(Pid), - Pid ! stop, - receive - {'EXIT', Pid, stop} -> - process_flag(trap_exit, Flag), - ok - end - end. - - -%%==================================================================== -%% Initialization -%%==================================================================== - -init(CallingPid, Mode, SFile) -> - register(?MODULE, self()), - - %% Graphics system - case catch dbg_ui_mon_win:init() of - {'EXIT', Reason} -> - CallingPid ! {error, Reason}; - GS -> - init2(CallingPid, Mode, SFile, GS) - end. - -init2(CallingPid, Mode, SFile, GS) -> - - %% Start Int if necessary and subscribe to information from it - Bool = case int:start() of - {ok, _Int} -> true; - {error, {already_started, _Int}} -> false - end, - int:subscribe(), - - %% Start other necessary stuff - dbg_ui_winman:start(), % Debugger window manager - - %% Create monitor window - Title = "Monitor", - Win = dbg_ui_mon_win:create_win(GS, Title, menus()), - Window = dbg_ui_mon_win:get_window(Win), - dbg_ui_winman:insert(Title, Window), - - %% Initial process state - State1 = #state{mode = Mode, - starter = Bool, - - gs = GS, - win = Win, - focus = undefined, - coords = {0,0}, - - intdir = element(2, file:get_cwd()), - pinfos = [], - - sfile = SFile, - changed = false - }, - - State2 = init_options(?TRACEWIN, % Trace Window - int:auto_attach(), % Auto Attach - int:stack_trace(), % Stack Trace - ?BACKTRACE, % Back Trace Size - State1), - - State3 = init_contents(int:interpreted(), % Modules - int:all_breaks(), % Breakpoints - int:snapshot(), % Processes - State2), - - %% Disable/enable functionality according to process in focus (none) - gui_enable_functions(State3#state.focus), - - CallingPid ! {initialization_complete, self()}, - - if - SFile =:= default -> - loop(State3); - true -> - loop(load_settings(SFile, State3)) - end. - -init_options(TraceWin, AutoAttach, StackTrace, BackTrace, State) -> - lists:foreach(fun(Area) -> - dbg_ui_mon_win:select(Area, true) - end, - TraceWin), - - case AutoAttach of - false -> ignore; - {Flags, _Function} -> - dbg_ui_mon_win:show_option(State#state.win, - auto_attach, Flags), - lists:foreach(fun(Flag) -> - dbg_ui_mon_win:select(map(Flag), true) - end, - Flags) - end, - - dbg_ui_mon_win:show_option(State#state.win, - stack_trace, StackTrace), - dbg_ui_mon_win:select(map(StackTrace), true), - - dbg_ui_mon_win:show_option(State#state.win, back_trace, BackTrace), - - State#state{tracewin=TraceWin, backtrace=BackTrace}. - -init_contents(Mods, Breaks, Processes, State) -> - Win2 = - lists:foldl(fun(Mod, Win) -> - dbg_ui_mon_win:add_module(Win,'Module',Mod) - end, - State#state.win, - Mods), - - Win3 = - lists:foldl(fun(Break, Win) -> - dbg_ui_mon_win:add_break(Win,'Break',Break) - end, - Win2, - Breaks), - - lists:foldl(fun(PidTuple, State0) -> - int_cmd({new_process, PidTuple}, State0) - end, - State#state{win=Win3}, - Processes). - - -%%==================================================================== -%% Main loop and message handling -%%==================================================================== - -loop(State) -> - receive - - stop -> - gui_cmd(stopped, State); - - %% From the GUI - GuiEvent when is_tuple(GuiEvent), element(1, GuiEvent) =:= gs -> - Cmd = dbg_ui_mon_win:handle_event(GuiEvent,State#state.win), - State2 = gui_cmd(Cmd, State), - loop(State2); - - %% From the interpreter process - {int, Cmd} -> - State2 = int_cmd(Cmd, State), - loop(State2); - - %% From the dbg_ui_interpret process - {dbg_ui_interpret, Dir} -> - loop(State#state{intdir=Dir}); - - %% From the dbg_ui_edit process - {dbg_ui_edit, 'Backtrace:', BackTrace} -> - dbg_ui_mon_win:show_option(State#state.win, - back_trace, BackTrace), - loop(State#state{backtrace=BackTrace}); - - %% From the dbg_ui_settings process - {dbg_ui_settings, SFile, Action} -> - State2 = case Action of - load -> load_settings(SFile, State); - save -> save_settings(SFile, State) - end, - loop(State2); - - %% From the dbg_ui_winman process (Debugger window manager) - {dbg_ui_winman, update_windows_menu, Data} -> - dbg_ui_winman:update_windows_menu(Data), - loop(State) - end. - -%%--Commands from the GUI--------------------------------------------- -%% Act upon a command from the GUI. In most cases, it is only necessary -%% to call a relevant int-function. int will then report when the action -%% has been taken. - -gui_cmd(ignore, State) -> - State; -gui_cmd(stopped, State) -> - if - State#state.starter =:= true -> int:stop(); - true -> int:auto_attach(false) - end, - exit(stop); -gui_cmd({coords, Coords}, State) -> - State#state{coords=Coords}; - -gui_cmd({shortcut, Key}, State) -> - case shortcut(Key) of - {always, Cmd} -> gui_cmd(Cmd, State); - {if_enabled, Cmd} -> - case dbg_ui_mon_win:is_enabled(Cmd) of - true -> gui_cmd(Cmd, State); - false -> State - end; - false -> State - end; - -%% File Menu -gui_cmd('Load Settings...', State) -> - Window = dbg_ui_mon_win:get_window(State#state.win), - dbg_ui_settings:start(Window, State#state.coords, - load, State#state.sfile), - State; -gui_cmd('Save Settings...', State) -> - Window = dbg_ui_mon_win:get_window(State#state.win), - dbg_ui_settings:start(Window, State#state.coords, - save, State#state.sfile), - State; -gui_cmd('Exit', State) -> - gui_cmd(stopped, State); - -%% Edit Menu -gui_cmd('Refresh', State) -> - int:clear(), - Win = dbg_ui_mon_win:clear_processes(State#state.win), - gui_enable_functions(undefined), - State2 = State#state{win=Win, focus=undefined, pinfos=[]}, - lists:foldl(fun(PidTuple, S) -> - int_cmd({new_process,PidTuple}, S) - end, - State2, - int:snapshot()); -gui_cmd('Kill All', State) -> - lists:foreach(fun(PInfo) -> - case PInfo#pinfo.status of - exit -> ignore; - _Status -> exit(PInfo#pinfo.pid, kill) - end - end, - State#state.pinfos), - State; - -%% Module Menu -gui_cmd('Interpret...', State) -> - dbg_ui_interpret:start(State#state.gs, State#state.coords, - State#state.intdir, State#state.mode), - State; -gui_cmd('Delete All Modules', State) -> - lists:foreach(fun(Mod) -> int:nn(Mod) end, int:interpreted()), - State; -gui_cmd({module, Mod, What}, State) -> - case What of - delete -> int:nn(Mod); - view -> dbg_ui_view:start(State#state.gs, Mod) - end, - State; - -%% Process Menu -gui_cmd('Step', State) -> - int:step((State#state.focus)#pinfo.pid), - State; -gui_cmd('Next', State) -> - int:next((State#state.focus)#pinfo.pid), - State; -gui_cmd('Continue', State) -> - int:continue((State#state.focus)#pinfo.pid), - State; -gui_cmd('Finish ', State) -> - int:finish((State#state.focus)#pinfo.pid), - State; -gui_cmd('Attach', State) -> - Pid = (State#state.focus)#pinfo.pid, - case dbg_ui_winman:is_started(dbg_ui_trace:title(Pid)) of - true -> ignore; - false -> int:attach(Pid, trace_function(State)) - end, - State; -gui_cmd('Kill', State) -> - exit((State#state.focus)#pinfo.pid, kill), - State; - -%% Break Menu -gui_cmd('Line Break...', State) -> - dbg_ui_break:start(State#state.gs, State#state.coords, line), - State; -gui_cmd('Conditional Break...', State) -> - dbg_ui_break:start(State#state.gs, State#state.coords, conditional), - State; -gui_cmd('Function Break...', State) -> - dbg_ui_break:start(State#state.gs, State#state.coords, function), - State; -gui_cmd('Enable All', State) -> - Breaks = int:all_breaks(), - lists:foreach(fun ({{Mod, Line}, _Options}) -> - int:enable_break(Mod, Line) - end, - Breaks), - State; -gui_cmd('Disable All', State) -> - Breaks = int:all_breaks(), - lists:foreach(fun ({{Mod, Line}, _Options}) -> - int:disable_break(Mod, Line) - end, - Breaks), - State; -gui_cmd('Delete All', State) -> - int:no_break(), - State; -gui_cmd({break, {Mod, Line}, What}, State) -> - case What of - delete -> int:delete_break(Mod, Line); - {status, inactive} -> int:disable_break(Mod, Line); - {status, active} -> int:enable_break(Mod, Line); - {trigger, Action} -> int:action_at_break(Mod, Line, Action) - end, - State; - -%% Options Commands -gui_cmd({'Trace Window', TraceWin}, State) -> - State2 = State#state{tracewin=TraceWin}, - case State#state.attach of - false -> ignore; - {Flags, {dbg_ui_trace, start, StartFlags}} -> - case trace_function(State2) of - {_, _, StartFlags} -> ignore; - NewFunction -> % {_, _, NewStartFlags} - int:auto_attach(Flags, NewFunction) - end; - _AutoAttach -> ignore - end, - State2; -gui_cmd({'Auto Attach', When}, State) -> - if - When =:= [] -> int:auto_attach(false); - true -> - Flags = [map(Name) || Name <- When], - int:auto_attach(Flags, trace_function(State)) - end, - State; -gui_cmd({'Stack Trace', [Name]}, State) -> - int:stack_trace(map(Name)), - State; -gui_cmd('Back Trace Size...', State) -> - dbg_ui_edit:start(State#state.gs, State#state.coords, "Backtrace", - 'Backtrace:', {integer, State#state.backtrace}), - State; - -%% Help Menu -gui_cmd('Debugger', State) -> - HelpFile = filename:join([code:lib_dir(debugger), "doc", "html", "index.html"]), - Window = dbg_ui_mon_win:get_window(State#state.win), - tool_utils:open_help(Window, HelpFile), - State; - -gui_cmd({focus, Pid, Win}, State) -> - {value, PInfo} = - lists:keysearch(Pid, #pinfo.pid, State#state.pinfos), - gui_enable_functions(PInfo), - State#state{win=Win, focus=PInfo}; -gui_cmd(default, State) -> - case lists:member('Attach', menus(enabled, State#state.focus)) of - true -> gui_cmd('Attach', State); - false -> State - end. - -%%--Commands from the interpreter------------------------------------- - -int_cmd({interpret, Mod}, State) -> - Win = dbg_ui_mon_win:add_module(State#state.win, 'Module', Mod), - State#state{win=Win}; -int_cmd({no_interpret, Mod}, State) -> - Win = dbg_ui_mon_win:delete_module(State#state.win, Mod), - State#state{win=Win}; - -int_cmd({new_process, {Pid, Function, Status, Info}}, State) -> - - %% Create record with information about the process - Name = registered_name(Pid), - PInfo = #pinfo{pid=Pid, status=Status}, - - %% Update window - Win = dbg_ui_mon_win:add_process(State#state.win, - Pid, Name, Function, Status, Info), - - %% Store process information - PInfos = State#state.pinfos ++ [PInfo], - State#state{win=Win, pinfos=PInfos}; -int_cmd({new_status, Pid, Status, Info}, State) -> - - %% Find stored information about the process - PInfos = State#state.pinfos, - {value, PInfo} = lists:keysearch(Pid, #pinfo.pid, PInfos), - - %% Update process information - PInfo2 = PInfo#pinfo{status=Status}, - PInfos2 = lists:keyreplace(Pid, #pinfo.pid, PInfos, PInfo2), - State2 = State#state{pinfos=PInfos2}, - - %% Update window - dbg_ui_mon_win:update_process(State2#state.win, Pid, Status, Info), - case State2#state.focus of - #pinfo{pid=Pid} -> - gui_enable_functions(PInfo2), - State2#state{focus=PInfo2}; - _ -> - State2 - end; - -int_cmd({new_break, Break}, State) -> - Win = dbg_ui_mon_win:add_break(State#state.win, 'Break', Break), - State#state{win=Win}; -int_cmd({delete_break, Point}, State) -> - Win = dbg_ui_mon_win:delete_break(State#state.win, Point), - State#state{win=Win}; -int_cmd({break_options, Break}, State) -> - dbg_ui_mon_win:update_break(State#state.win, Break), - State; -int_cmd(no_break, State) -> - Win = dbg_ui_mon_win:clear_breaks(State#state.win), - State#state{win=Win}; -int_cmd({no_break, Mod}, State) -> - Win = dbg_ui_mon_win:clear_breaks(State#state.win, Mod), - State#state{win=Win}; - -int_cmd({auto_attach, AutoAttach}, State) -> - OnFlags = case AutoAttach of - false -> []; - {Flags, _Function} -> Flags - end, - OffFlags = [init, exit, break] -- OnFlags, - dbg_ui_mon_win:show_option(State#state.win, auto_attach, OnFlags), - lists:foreach(fun(Flag) -> - dbg_ui_mon_win:select(map(Flag), true) - end, - OnFlags), - lists:foreach(fun(Flag) -> - dbg_ui_mon_win:select(map(Flag), false) - end, - OffFlags), - State#state{attach=AutoAttach}; -int_cmd({stack_trace, Flag}, State) -> - dbg_ui_mon_win:show_option(State#state.win, stack_trace, Flag), - dbg_ui_mon_win:select(map(Flag), true), - State. - - -%%==================================================================== -%% GUI auxiliary functions -%%==================================================================== - -menus() -> - [{'File', [{'Load Settings...', 0}, - {'Save Settings...', 2}, - separator, - {'Exit', 0}]}, - {'Edit', [{'Refresh', no}, - {'Kill All', no}]}, - {'Module', [{'Interpret...', 0}, - {'Delete All Modules', no}, - separator]}, - {'Process', [{'Step', 0}, - {'Next', 0}, - {'Continue', 0}, - {'Finish ', 0}, - separator, - {'Attach', 0}, - {'Kill', no}]}, - {'Break', [{'Line Break...', 5}, - {'Conditional Break...', no}, - {'Function Break...', no}, - separator, - {'Enable All', no}, - {'Disable All', no}, - {'Delete All', 0}, - separator]}, - {'Options', [{'Trace Window', no, cascade, - [{'Button Area', no, check}, - {'Evaluator Area', no, check}, - {'Bindings Area', no, check}, - {'Trace Area', no, check}]}, - {'Auto Attach', no, cascade, - [{'First Call', no, check}, - {'On Break', no, check}, - {'On Exit', no, check}]}, - {'Stack Trace', no, cascade, - [{'Stack On, Tail', no, radio}, - {'Stack On, No Tail', no, radio}, - {'Stack Off', no, radio}]}, - {'Back Trace Size...', no}]}, - {'Help', [{'Debugger', no}]}]. - -menus(enabled, undefined) -> - []; -menus(disabled, undefined) -> - ['Step','Next','Continue','Finish ','Attach','Kill']; -menus(enabled, #pinfo{status=exit}) -> - ['Attach']; -menus(disabled, #pinfo{status=exit}) -> - ['Step','Next','Continue','Finish ','Kill']; -menus(enabled, #pinfo{status=break}) -> - ['Step','Next','Continue','Finish ','Attach','Kill']; -menus(disabled, #pinfo{status=break}) -> - []; -menus(enabled, _PInfo) -> - ['Attach','Kill']; -menus(disabled, _PInfo) -> - ['Step','Next','Continue','Finish ']. - -shortcut(l) -> {always, 'Load Settings...'}; -shortcut(v) -> {always, 'Save Settings...'}; -shortcut(e) -> {always, 'Exit'}; - -shortcut(i) -> {always, 'Interpret...'}; - -shortcut(s) -> {if_enabled, 'Step'}; -shortcut(n) -> {if_enabled, 'Next'}; -shortcut(c) -> {if_enabled, 'Continue'}; -shortcut(f) -> {if_enabled, 'Finish '}; -shortcut(a) -> {if_enabled, 'Attach'}; - -shortcut(b) -> {always, 'Line Break...'}; -shortcut(d) -> {always, 'Delete All'}; - -shortcut(_) -> false. - -%% Enable/disable functionality depending on the state of the process -%% currently in Focus -gui_enable_functions(PInfo) -> - Enabled = menus(enabled, PInfo), - Disabled = menus(disabled, PInfo), - dbg_ui_mon_win:enable(Enabled, true), - dbg_ui_mon_win:enable(Disabled, false). - -%% Map values used by int to/from GUI names -map('First Call') -> init; % Auto attach -map('On Exit') -> exit; -map('On Break') -> break; -map(init) -> 'First Call'; -map(exit) -> 'On Exit'; -map(break) -> 'On Break'; - -map('Stack On, Tail') -> all; % Stack trace -map('Stack On, No Tail') -> no_tail; -map('Stack Off') -> false; -map(all) -> 'Stack On, Tail'; -map(true) -> 'Stack On, Tail'; -map(no_tail) -> 'Stack On, No Tail'; -map(false) -> 'Stack Off'. - - -%%==================================================================== -%% Debugger settings -%%==================================================================== - -load_settings(SFile, State) -> - case file:read_file(SFile) of - {ok, Binary} -> - case catch binary_to_term(Binary) of - {debugger_settings, Settings} -> - load_settings2(Settings, - State#state{sfile=SFile, - changed=false}); - _Error -> State - end; - {error, _Reason} -> State - end. - -load_settings2(Settings, State) -> - {TraceWin, AutoAttach, StackTrace, BackTrace, Files, Breaks} = - Settings, - - TraceWinAll = ['Button Area', 'Evaluator Area', 'Bindings Area', - 'Trace Area'], - lists:foreach(fun(Area) -> dbg_ui_mon_win:select(Area, true) end, - TraceWin), - lists:foreach(fun(Area) -> dbg_ui_mon_win:select(Area, false) end, - TraceWinAll--TraceWin), - - case AutoAttach of - false -> int:auto_attach(false); - {Flags, Function} -> int:auto_attach(Flags, Function) - end, - - int:stack_trace(StackTrace), - - dbg_ui_mon_win:show_option(State#state.win, back_trace, BackTrace), - - case State#state.mode of - local -> lists:foreach(fun(File) -> int:i(File) end, Files); - global -> lists:foreach(fun(File) -> int:ni(File) end, Files) - end, - lists:foreach(fun(Break) -> - {{Mod, Line}, [Status, Action, _, Cond]} = - Break, - int:break(Mod, Line), - if - Status =:= inactive -> - int:disable_break(Mod, Line); - true -> ignore - end, - if - Action/=enable -> - int:action_at_break(Mod,Line,Action); - true -> ignore - end, - case Cond of - CFunction when is_tuple(CFunction) -> - int:test_at_break(Mod,Line,CFunction); - null -> ignore - end - end, - Breaks), - - State#state{tracewin=TraceWin, backtrace=BackTrace}. - -save_settings(SFile, State) -> - Settings = {State#state.tracewin, - int:auto_attach(), - int:stack_trace(), - State#state.backtrace, - [int:file(Mod) || Mod <- int:interpreted()], - int:all_breaks()}, - Binary = term_to_binary({debugger_settings, Settings}), - case file:write_file(SFile, Binary) of - ok -> - State#state{sfile=SFile, changed=false}; - {error, _Reason} -> - State - end. - - -%%==================================================================== -%% Other internal functions -%%==================================================================== - -registered_name(Pid) -> - %% Yield in order to give Pid more time to register its name - timer:sleep(200), - - Node = node(Pid), - if - Node =:= node() -> - case erlang:process_info(Pid, registered_name) of - {registered_name, Name} -> Name; - _ -> undefined - end; - true -> - case rpc:call(Node,erlang,process_info, - [Pid,registered_name]) of - {registered_name, Name} -> Name; - _ -> undefined - end - end. - -trace_function(State) -> - {dbg_ui_trace, start, [State#state.tracewin,State#state.backtrace]}. |