aboutsummaryrefslogtreecommitdiffstats
path: root/lib/debugger
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2011-03-31 07:22:02 +0200
committerBjörn Gustavsson <[email protected]>2011-08-16 08:58:47 +0200
commit3ccc4730e54f0f9e86bf96360b7600ab8c9e1d47 (patch)
tree994796c3b34c131d7db98295e13e7cfdcb2b6982 /lib/debugger
parent778eece5cdc55f19daf354ed374a556dde37cafa (diff)
downloadotp-3ccc4730e54f0f9e86bf96360b7600ab8c9e1d47.tar.gz
otp-3ccc4730e54f0f9e86bf96360b7600ab8c9e1d47.tar.bz2
otp-3ccc4730e54f0f9e86bf96360b7600ab8c9e1d47.zip
Rewrite stack handling
Problems with the current stack implementation: * The GUI assumes that the stack frame pushed on the stack is level 2. If the 'no_tail' option is set for the process, there may not be an entry for level 2. * In each stack entry, the line number is the line number of the caller, not the line number for the function in the 'mfa' field as might be expected. That complicates generation of a stacktrace with line number information. Change the implementation as follows: * Keep the information for the current function (its MFA and current line number) in the #ieval{} record. Don't push it onto the stack. Only push the information when another function is called. That will ensure that the MFA and the line number is found in the same stack entry. That also has the advantage that if the 'no_tail' option is set, the stack not need to be modified for tail-recursive calls. * Make sure that there always is an entry for level two.
Diffstat (limited to 'lib/debugger')
-rw-r--r--lib/debugger/src/dbg_icmd.erl4
-rw-r--r--lib/debugger/src/dbg_ieval.erl61
-rw-r--r--lib/debugger/src/dbg_istk.erl49
3 files changed, 58 insertions, 56 deletions
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index c158aad1cf..b230efaa7a 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -345,8 +345,8 @@ handle_user_msg({get,stack_frame,From,{Dir,SP}}, _Status, _Bs,_Ieval) ->
reply(From, stack_frame, dbg_istk:stack_frame(Dir, SP));
handle_user_msg({get,messages,From,_}, _Status, _Bs, _Ieval) ->
reply(From, messages, messages());
-handle_user_msg({get,backtrace,From,N}, _Status, _Bs, _Ieval) ->
- reply(From, backtrace, dbg_istk:backtrace(N)).
+handle_user_msg({get,backtrace,From,N}, _Status, _Bs, Ieval) ->
+ reply(From, backtrace, dbg_istk:backtrace(N, Ieval)).
set_stack_trace(true) ->
set_stack_trace(all);
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index e343e6f1e0..445eba3346 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -382,10 +382,11 @@ catch_value(throw, Reason) ->
%% Top level function of meta evaluator.
%% Return message to be replied to the target process.
%%--------------------------------------------------------------------
-eval_mfa(Debugged, M, F, As, Ieval) ->
+eval_mfa(Debugged, M, F, As, #ieval{level=Le}=Ieval0) ->
Int = get(int),
Bs = erl_eval:new_bindings(),
- try eval_function(M,F,As,Bs,extern,Ieval#ieval{top=true}) of
+ Ieval = Ieval0#ieval{level=Le+1,top=true},
+ try do_eval_function(M, F, As, Bs, extern, Ieval) of
{value, Val, _Bs} ->
{ready, Val}
catch
@@ -397,18 +398,21 @@ eval_mfa(Debugged, M, F, As, Ieval) ->
{exception, {Class, Reason, get(stacktrace)}}
end.
-eval_function(Mod, Fun, As0, Bs0, _Called, Ieval) when is_function(Fun);
- Mod =:= ?MODULE,
- Fun =:= eval_fun ->
+eval_function(Mod, Name, As, Bs, Called, Ieval0) ->
+ Ieval = dbg_istk:push(Bs, Ieval0),
+ Res = do_eval_function(Mod, Name, As, Bs, Called, Ieval),
+ dbg_istk:pop(),
+ Res.
+
+do_eval_function(Mod, Fun, As0, Bs0, _, Ieval) when is_function(Fun);
+ Mod =:= ?MODULE,
+ Fun =:= eval_fun ->
#ieval{level=Le, line=Li, top=Top} = Ieval,
case lambda(Fun, As0) of
{Cs,Module,Name,As,Bs} ->
- dbg_istk:push({Module,Name,As}, Bs0, Ieval),
trace(call_fun, {Le,Li,Name,As}),
{value, Val, _Bs} =
- fnk_clauses(Cs, Module, Name, As, Bs,
- Ieval#ieval{level=Le+1}),
- dbg_istk:pop(),
+ fnk_clauses(Cs, Module, Name, As, Bs, Ieval),
trace(return, {Le,Val}),
{value, Val, Bs0};
@@ -416,12 +420,9 @@ eval_function(Mod, Fun, As0, Bs0, _Called, Ieval) when is_function(Fun);
trace(call_fun, {Le,Li,Fun,As0}),
{value, {dbg_apply,erlang,apply,[Fun,As0]}, Bs0};
not_interpreted ->
- dbg_istk:push({Fun,As0}, Bs0, Ieval),
trace(call_fun, {Le,Li,Fun,As0}),
{value, Val, _Bs} =
- debugged_cmd({apply,erlang,apply,[Fun,As0]},Bs0,
- Ieval#ieval{level=Le+1}),
- dbg_istk:pop(),
+ debugged_cmd({apply,erlang,apply,[Fun,As0]}, Bs0, Ieval),
trace(return, {Le,Val}),
{value, Val, Bs0};
@@ -433,22 +434,19 @@ eval_function(Mod, Fun, As0, Bs0, _Called, Ieval) when is_function(Fun);
end;
%% Common Test adaptation
-eval_function(ct_line, line, As, Bs, extern, #ieval{level=Le}=Ieval) ->
+do_eval_function(ct_line, line, As, Bs, extern, #ieval{level=Le}=Ieval) ->
debugged_cmd({apply,ct_line,line,As}, Bs, Ieval#ieval{level=Le+1}),
{value, ignore, Bs};
-eval_function(Mod, Name, As0, Bs0, Called, Ieval) ->
- #ieval{level=Le, line=Li, top=Top} = Ieval,
-
- dbg_istk:push({Mod,Name,As0}, Bs0, Ieval),
+do_eval_function(Mod, Name, As0, Bs0, Called, Ieval0) ->
+ #ieval{level=Le,line=Li,top=Top} = Ieval0,
trace(call, {Called, {Le,Li,Mod,Name,As0}}),
-
+ Ieval = Ieval0#ieval{module=Mod,function=Name,arguments=As0},
case get_function(Mod, Name, As0, Called) of
Cs when is_list(Cs) ->
{value, Val, _Bs} =
fnk_clauses(Cs, Mod, Name, As0, erl_eval:new_bindings(),
- Ieval#ieval{level=Le+1}),
- dbg_istk:pop(),
+ Ieval),
trace(return, {Le,Val}),
{value, Val, Bs0};
@@ -456,9 +454,7 @@ eval_function(Mod, Name, As0, Bs0, Called, Ieval) ->
{value, {dbg_apply,Mod,Name,As0}, Bs0};
not_interpreted ->
{value, Val, _Bs} =
- debugged_cmd({apply,Mod,Name,As0}, Bs0,
- Ieval#ieval{level=Le+1}),
- dbg_istk:pop(),
+ debugged_cmd({apply,Mod,Name,As0}, Bs0, Ieval),
trace(return, {Le,Val}),
{value, Val, Bs0};
@@ -807,10 +803,11 @@ expr({dbg,Line,exit,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
%% Call to "safe" BIF, ie a BIF that can be executed in Meta process
expr({safe_bif,Line,M,F,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
- {As,Bs} = eval_list(As0, Bs0, Ieval),
+ Ieval1 = Ieval0#ieval{line=Line},
+ {As,Bs} = eval_list(As0, Bs0, Ieval1),
trace(bif, {Le,Line,M,F,As}),
- dbg_istk:push({M,F,As}, Bs0, Ieval),
+ Ieval2 = dbg_istk:push(Bs0, Ieval1),
+ Ieval = Ieval2#ieval{module=M,function=F,arguments=As},
{_,Value,_} = Res = safe_bif(M, F, As, Bs, Ieval),
trace(return, {Le,Value}),
dbg_istk:pop(),
@@ -818,12 +815,12 @@ expr({safe_bif,Line,M,F,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
%% Call to a BIF that must be evaluated in the correct process
expr({bif,Line,M,F,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
- {As,Bs} = eval_list(As0, Bs0, Ieval),
+ Ieval1 = Ieval0#ieval{line=Line},
+ {As,Bs} = eval_list(As0, Bs0, Ieval1),
trace(bif, {Le,Line,M,F,As}),
- dbg_istk:push({M,F,As}, Bs0, Ieval),
- {_,Value,_} =
- Res = debugged_cmd({apply,M,F,As}, Bs, Ieval#ieval{level=Le+1}),
+ Ieval2 = dbg_istk:push(Bs0, Ieval1),
+ Ieval = Ieval2#ieval{module=M,function=F,arguments=As},
+ {_,Value,_} = Res = debugged_cmd({apply,M,F,As}, Bs, Ieval),
trace(return, {Le,Value}),
dbg_istk:pop(),
Res;
diff --git a/lib/debugger/src/dbg_istk.erl b/lib/debugger/src/dbg_istk.erl
index b852e1f8fd..2e7b114fab 100644
--- a/lib/debugger/src/dbg_istk.erl
+++ b/lib/debugger/src/dbg_istk.erl
@@ -18,9 +18,9 @@
%%
-module(dbg_istk).
-export([init/0,to_external/0,from_external/1,
- push/3,pop/0,pop/1,stack_level/0,
+ push/2,pop/0,pop/1,stack_level/0,
exception_stacktrace/2,
- bindings/1,stack_frame/2,backtrace/1,
+ bindings/1,stack_frame/2,backtrace/2,
in_use_p/2]).
-include("dbg_ieval.hrl").
@@ -30,7 +30,6 @@
-record(e,
{level, %Level
mfa, %{Mod,Func,Args|Arity}|{Fun,Args}
- cm, %Module called from
line, %Line called from
bindings
}).
@@ -61,17 +60,17 @@ init(Stack) ->
%% false - nothing is pushed
%% Whenever a function returns, the corresponding call frame is popped.
-push(MFA, Bs, #ieval{level=Le,module=Cm,line=Li,top=Lc}) ->
- Entry = #e{level=Le,mfa=MFA,cm=Cm,line=Li,bindings=Bs},
+push(Bs, #ieval{level=Le,module=Mod,function=Name,arguments=As,
+ line=Li,top=Lc}=Ieval) ->
+ Entry = #e{level=Le,mfa={Mod,Name,As},line=Li,bindings=Bs},
case get(trace_stack) of
- false -> ignore;
+ false ->
+ Ieval#ieval{level=Le+1};
no_tail when Lc ->
- case get(?STACK) of
- [] -> put(?STACK, [Entry]);
- [_Entry|Entries] -> put(?STACK, [Entry|Entries])
- end;
+ Ieval;
_ -> % all | no_tail when Lc =:= false
- put(?STACK, [Entry|get(?STACK)])
+ put(?STACK, [Entry|get(?STACK)]),
+ Ieval#ieval{level=Le+1}
end.
pop() ->
@@ -117,13 +116,15 @@ stack_level([#e{level=Le}|_]) -> Le.
%% function and convert argument lists to arity for all but the topmost
%% entry (and funs).
-exception_stacktrace(complete, #ieval{}) ->
- fix_stacktrace(1);
+exception_stacktrace(complete, #ieval{}=Ieval) ->
+ #ieval{module=Mod,function=Name,arguments=As} = Ieval,
+ Stk = [#e{mfa={Mod,Name,As}}|get(?STACK)],
+ fix_stacktrace(Stk);
exception_stacktrace(no_current, #ieval{}) ->
- fix_stacktrace(2).
+ fix_stacktrace(get(?STACK)).
-fix_stacktrace(Start) ->
- case fix_stacktrace2(sublist(get(?STACK), Start, 3)) of
+fix_stacktrace(Stk) ->
+ case fix_stacktrace2(sublist(Stk, 1, 3)) of
[] ->
[];
[H|T] ->
@@ -180,13 +181,15 @@ stack_frame(up, SP) ->
stack_frame(down, SP) ->
stack_frame(SP, down, lists:reverse(get(?STACK))).
-stack_frame(SP, up, [#e{level=Le,cm=Cm,line=Li,bindings=Bs}|_]) when Le < SP ->
+stack_frame(SP, up, [#e{level=Le,mfa={Cm,_,_},line=Li,bindings=Bs}|_])
+ when Le < SP ->
{Le,{Cm,Li},Bs};
-stack_frame(SP, down, [#e{level=Le,cm=Cm,line=Li,bindings=Bs}|_]) when Le > SP ->
+stack_frame(SP, down, [#e{level=Le,mfa={Cm,_,_},line=Li,bindings=Bs}|_])
+ when Le > SP ->
{Le,{Cm,Li},Bs};
stack_frame(SP, Dir, [#e{level=SP}|Stack]) ->
case Stack of
- [#e{level=Le,cm=Cm,line=Li,bindings=Bs}|_] ->
+ [#e{level=Le,mfa={Cm,_,_},line=Li,bindings=Bs}|_] ->
{Le,{Cm,Li},Bs};
[] when Dir =:= up ->
top;
@@ -200,10 +203,12 @@ stack_frame(SP, Dir, [_Entry|Stack]) ->
%% HowMany = all | int()
%% Backtrace = {Le, MFA}
%% Return all/the last N called functions, in reversed call order
-backtrace(HowMany) ->
+backtrace(HowMany, Ieval) ->
+ #ieval{level=Level,module=Mod,function=Name,arguments=As} = Ieval,
+ Stack0 = [#e{level=Level,mfa={Mod,Name,As}}|get(?STACK)],
Stack = case HowMany of
- all -> get(?STACK);
- N -> lists:sublist(get(?STACK), N)
+ all -> Stack0;
+ N -> lists:sublist(Stack0, N)
end,
[{Le,MFA} || #e{level=Le,mfa=MFA} <- Stack].