dbg_ui_mon.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 744 行 · 第 1/2 页

ERL
744
字号
%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-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 Menugui_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 Menugui_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 Menugui_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 Menugui_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 Menugui_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;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?