aboutsummaryrefslogtreecommitdiffstats
path: root/lib/debugger/src/dbg_debugged.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/debugger/src/dbg_debugged.erl')
-rw-r--r--lib/debugger/src/dbg_debugged.erl118
1 files changed, 118 insertions, 0 deletions
diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl
new file mode 100644
index 0000000000..b56ebef14a
--- /dev/null
+++ b/lib/debugger/src/dbg_debugged.erl
@@ -0,0 +1,118 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. 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_debugged).
+
+%% External exports
+-export([eval/3]).
+
+%%====================================================================
+%% External exports
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% eval(Mod, Func, Args) -> Value
+%% Main entry point from external (non-interpreted) code.
+%% Called via the error handler.
+%%--------------------------------------------------------------------
+eval(Mod, Func, Args) ->
+ SaveStacktrace = erlang:get_stacktrace(),
+ Meta = dbg_ieval:eval(Mod, Func, Args),
+ Mref = erlang:monitor(process, Meta),
+ msg_loop(Meta, Mref, SaveStacktrace).
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
+
+msg_loop(Meta, Mref, SaveStacktrace) ->
+ receive
+
+ %% Evaluated function has returned a value
+ {sys, Meta, {ready, Val}} ->
+ demonitor(Mref),
+
+ %% Restore original stacktrace and return the value
+ try erlang:raise(throw, stack, SaveStacktrace)
+ catch
+ throw:stack ->
+ case Val of
+ {dbg_apply,M,F,A} ->
+ apply(M, F, A);
+ _ ->
+ Val
+ end
+ end;
+
+ %% Evaluated function raised an (uncaught) exception
+ {sys, Meta, {exception,{Class,Reason,Stacktrace}}} ->
+ demonitor(Mref),
+
+ %% ...raise the same exception
+ erlang:error(erlang:raise(Class, Reason, Stacktrace),
+ [Class,Reason,Stacktrace]);
+
+ %% Meta is evaluating a receive, must be done within context
+ %% of real (=this) process
+ {sys, Meta, {'receive',Msg}} ->
+ receive Msg -> Meta ! {self(), rec_acked} end,
+ msg_loop(Meta, Mref, SaveStacktrace);
+
+ %% Meta needs something evaluated within context of real process
+ {sys, Meta, {command, Command, Stacktrace}} ->
+ Reply = handle_command(Command, Stacktrace),
+ Meta ! {sys, self(), Reply},
+ msg_loop(Meta, Mref, SaveStacktrace);
+
+ %% Meta has terminated
+ %% Must be due to int:stop() (or -heaven forbid- a debugger bug)
+ {'DOWN', Mref, _, _, Reason} ->
+
+ %% Restore original stacktrace and return a dummy value
+ try erlang:raise(throw, stack, SaveStacktrace)
+ catch
+ throw:stack ->
+ {interpreter_terminated, Reason}
+ end
+ end.
+
+handle_command(Command, Stacktrace) ->
+ try reply(Command)
+ catch Class:Reason ->
+ Stacktrace2 = stacktrace_f(erlang:get_stacktrace()),
+ {exception, {Class,Reason,Stacktrace2++Stacktrace}}
+ end.
+
+reply({apply,M,F,As}) ->
+ {value, erlang:apply(M,F,As)};
+reply({eval,Expr,Bs}) ->
+ erl_eval:expr(Expr, Bs). % {value, Value, Bs2}
+
+%% Demonitor and delete message from inbox
+%%
+demonitor(Mref) ->
+ erlang:demonitor(Mref),
+ receive {'DOWN',Mref,_,_,_} -> ok
+ after 0 -> ok
+ end.
+
+%% Fix stacktrace - keep all above call to this module.
+%%
+stacktrace_f([]) -> [];
+stacktrace_f([{?MODULE,_,_}|_]) -> [];
+stacktrace_f([F|S]) -> [F|stacktrace_f(S)].