37
27
%%--------------------------------------------------------------------
38
28
%% eval(Mod, Func, Args) -> Value
39
29
%% Main entry point from external (non-interpreted) code.
40
%% Called via the error handler when a breakpoint is hit.
30
%% Called via the error handler.
41
31
%%--------------------------------------------------------------------
42
32
eval(Mod, Func, Args) ->
43
Meta = dbg_imeta:eval(Mod, Func, Args),
46
%%====================================================================
48
%%====================================================================
50
follow(_Fol, M, F, As) ->
33
SaveStacktrace = erlang:get_stacktrace(),
34
Meta = dbg_ieval:eval(Mod, Func, Args),
35
Mref = erlang:monitor(process, Meta),
36
msg_loop(Meta, Mref, SaveStacktrace).
54
38
%%====================================================================
55
39
%% Internal functions
56
40
%%====================================================================
59
case catch msg_loop(Meta) of
64
?DBG("EXIT ~p~n",[Reason0]),
65
Reason = remove_debugger_calls(Reason0),
66
Meta ! {sys,self(),{exited_nocatch,Reason}},
68
{'EXIT',Meta,Reason} ->
69
?DBG("EXIT ~p~n",[Reason]),
72
?DBG("Thrown ~p~n",[Thrown]),
73
Meta ! {sys,self(),{thrown_nocatch,Thrown}},
80
?DBG("Command~p~n",[Command]),
81
handle_command(Meta, Command);
82
{'EXIT',Meta,Reason} ->
86
handle_command(Meta, {ready,Val}) ->
88
handle_command(Meta, {'receive',Msg}) ->
91
Meta ! {self(),rec_acked}
94
handle_command(_Meta, {exit,Reason}) ->
96
handle_command(Meta, {bif,Mod,Name,As,Where,Followed}) ->
97
Res = bif(Mod, Name, As, Followed, Where),
98
Meta ! {sys,self(),{apply_result,Res}},
100
handle_command(Meta, {catch_bif,Mod,Name,As,Where,Followed}) ->
101
send_result(Meta, catch_bif(Meta, Mod, Name, As, Followed, Where)),
103
handle_command(Meta, {apply,Mod,Fnk,As}) ->
104
Res = apply(Mod, Fnk, As),
105
Meta ! {sys,self(),{apply_result,Res}},
107
handle_command(Meta, {catch_apply,Mod,Fnk,As}) ->
108
send_result(Meta, catch_apply(Meta, Mod, Fnk, As)),
110
handle_command(Meta, {eval,Expr,Bs0}) ->
112
case catch {Ref,erl_eval:expr(Expr, Bs0)} of
113
{Ref,{value,V,Bs}} ->
114
Meta ! {sys,self(),{eval_result,V,Bs}};
116
Meta ! {sys,self(),{thrown,Other}}
120
send_result(Meta, {catch_normal,Meta,Res}) ->
121
Meta ! {sys,self(),{apply_result,Res}};
122
send_result(Meta, Thrown) ->
123
Meta ! {sys,self(),{thrown,Thrown}}.
125
%%-- Return tuple if apply evaluates normally, otherwise the
126
%%-- surrounding catch notices the unnormal exit.
128
catch_apply(Meta, Mod, Fnk, As) ->
130
Res0 = (catch {Ref, apply(Mod, Fnk, As)}),
132
{'EXIT', Reason} -> {'EXIT', remove_debugger_calls(Reason)};
134
{catch_normal,Meta,Res};
139
catch_bif(Meta, Mod, Name, As, Followed, Where) ->
140
Res = (catch bif(Mod, Name, As, Followed, Where)),
142
{'EXIT', Reason} -> {'EXIT', remove_debugger_calls(Reason)};
144
{catch_normal,Meta,Res}
147
remove_debugger_calls({Reason,BT}) when is_list(BT) ->
148
{Reason, remove_debugger_calls(BT, [])};
149
remove_debugger_calls(Reason) ->
151
remove_debugger_calls([{?MODULE, _F, _A}|R], Acc) ->
152
remove_debugger_calls(R,Acc);
153
remove_debugger_calls([Other|R], Acc) ->
154
remove_debugger_calls(R, [Other|Acc]);
155
remove_debugger_calls([],Acc) ->
157
remove_debugger_calls(What, Acc) ->
158
lists:reverse([What|Acc]).
160
%% bif(Mod, Name, Arguments)
163
bif(Mod, Name, As, false, Where) ->
164
erts_debug:apply(Mod, Name, As, Where);
165
bif(erlang, spawn, [M,F,As], Attached, _Where) ->
166
spawn(?MODULE,follow,[Attached,M,F,As]);
167
bif(erlang, spawn_link, [M,F,As], Attached, _Where) ->
168
spawn_link(?MODULE,follow,[Attached,M,F,As]);
169
bif(erlang, spawn, [N,M,F,As], Attached, _Where) ->
170
spawn(N,?MODULE,follow,[Attached,M,F,As]);
171
bif(erlang, spawn_link, [N,M,F,As], Attached, _Where) ->
172
spawn_link(N,?MODULE,follow,[Attached,M,F,As]).
174
%%---------------------------------------------------
176
%%-- The Meta process shall initiate all exits!
177
%%---------------------------------------------------
181
{sys,Meta,{exit,Reason}} ->
183
{'EXIT',Meta,Reason} ->
42
msg_loop(Meta, Mref, SaveStacktrace) ->
45
%% Evaluated function has returned a value
46
{sys, Meta, {ready, Val}} ->
49
%% Restore original stacktrace and return the value
50
try erlang:raise(throw, stack, SaveStacktrace)
61
%% Evaluated function raised an (uncaught) exception
62
{sys, Meta, {exception,{Class,Reason,Stacktrace}}} ->
65
%% ...raise the same exception
66
erlang:error(erlang:raise(Class, Reason, Stacktrace),
67
[Class,Reason,Stacktrace]);
69
%% Meta is evaluating a receive, must be done within context
70
%% of real (=this) process
71
{sys, Meta, {'receive',Msg}} ->
72
receive Msg -> Meta ! {self(), rec_acked} end,
73
msg_loop(Meta, Mref, SaveStacktrace);
75
%% Meta needs something evaluated within context of real process
76
{sys, Meta, {command, Command, Stacktrace}} ->
77
Reply = handle_command(Command, Stacktrace),
78
Meta ! {sys, self(), Reply},
79
msg_loop(Meta, Mref, SaveStacktrace);
81
%% Meta has terminated
82
%% Must be due to int:stop() (or -heaven forbid- a debugger bug)
83
{'DOWN', Mref, _, _, Reason} ->
85
%% Restore original stacktrace and return a dummy value
86
try erlang:raise(throw, stack, SaveStacktrace)
89
{interpreter_terminated, Reason}
93
handle_command(Command, Stacktrace) ->
96
Stacktrace2 = stacktrace_f(erlang:get_stacktrace()),
97
{exception, {Class,Reason,Stacktrace2++Stacktrace}}
100
reply({apply,M,F,As}) ->
101
{value, erlang:apply(M,F,As)};
102
reply({eval,Expr,Bs}) ->
103
erl_eval:expr(Expr, Bs). % {value, Value, Bs2}
105
%% Demonitor and delete message from inbox
108
erlang:demonitor(Mref),
109
receive {'DOWN',Mref,_,_,_} -> ok
113
%% Fix stacktrace - keep all above call to this module.
115
stacktrace_f([]) -> [];
116
stacktrace_f([{?MODULE,_,_}|_]) -> [];
117
stacktrace_f([F|S]) -> [F|stacktrace_f(S)].