aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2011-03-31 08:01:38 +0200
committerBjörn Gustavsson <[email protected]>2011-08-16 08:58:47 +0200
commit059dab74c2930eb5627737c336c428ca30f290c5 (patch)
treeee74e2ef6f5109bd8d6b78cbf5e97c0ed795721f /lib
parente0fe23461cc94a80e02a9542ab2182f62badd5de (diff)
downloadotp-059dab74c2930eb5627737c336c428ca30f290c5.tar.gz
otp-059dab74c2930eb5627737c336c428ca30f290c5.tar.bz2
otp-059dab74c2930eb5627737c336c428ca30f290c5.zip
Make stacktraces in exceptions more similar to BEAM's stacktraces
When an exception was generated from interpreted code, the stacktrace would not look exactly like BEAM's stacktraces. There would generally be fewer entries (never more than three), and the top entry would always have MFAs with the actual arguments (rather than the arity). There are two good reasons for making the stacktraces as similar as possible: * Code that examines a stacktrace can behave differently in the interpreted and BEAM code if the stacktraces are different. * It is easier to test the debugger if test suites for other applications (such as the emulator) can be run with the debugger with as few modifications as possible.
Diffstat (limited to 'lib')
-rw-r--r--lib/debugger/src/dbg_ieval.erl24
-rw-r--r--lib/debugger/src/dbg_istk.erl83
2 files changed, 55 insertions, 52 deletions
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index fe7f9af1a9..32848a00ff 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -168,10 +168,18 @@ check_exit_msg(_Msg, _Bs, _Ieval) ->
%% and then raise the exception.
%%--------------------------------------------------------------------
exception(Class, Reason, Bs, Ieval) ->
- exception(Class, Reason, dbg_istk:delayed_stacktrace(Ieval),
- Bs, Ieval).
-
-exception(Class, Reason, Stacktrace, Bs, #ieval{module=M, line=Line}) ->
+ exception(Class, Reason, Bs, Ieval, false).
+
+exception(Class, Reason, Bs, Ieval, false) ->
+ do_exception(Class, Reason,
+ dbg_istk:delayed_stacktrace(no_args, Ieval),
+ Bs, Ieval);
+exception(Class, Reason, Bs, Ieval, true) ->
+ do_exception(Class, Reason,
+ dbg_istk:delayed_stacktrace(include_args, Ieval),
+ Bs, Ieval).
+
+do_exception(Class, Reason, Stacktrace, Bs, #ieval{module=M, line=Line}) ->
ExitInfo = {{M,Line}, Bs, dbg_istk:to_external()},
put(exit_info, ExitInfo),
put(stacktrace, Stacktrace),
@@ -249,7 +257,7 @@ meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) ->
Depth = max(0, Depth0 - length(Stk)),
Stk ++ MakeStk0(Depth)
end,
- exception(Class, Reason, MakeStk, Bs, Ieval);
+ do_exception(Class, Reason, MakeStk, Bs, Ieval);
%% Error must have occured within a re-entry to
%% interpreted code, simply raise the exception
@@ -463,7 +471,7 @@ do_eval_function(Mod, Name, As0, Bs0, Called, Ieval0) ->
{value, Val, Bs0};
undef ->
- exception(error, undef, Bs0, Ieval)
+ exception(error, undef, Bs0, Ieval, true)
end.
lambda(eval_fun, [Cs,As,Bs,{Mod,Name}=F]) ->
@@ -580,7 +588,7 @@ fnk_clauses([{clause,Line,Pars,Gs,Body}|Cs], M, F, As, Bs0, Ieval) ->
fnk_clauses(Cs, M, F, As, Bs0, Ieval)
end;
fnk_clauses([], _M, _F, _As, Bs, Ieval) ->
- exception(error, function_clause, Bs, Ieval).
+ exception(error, function_clause, Bs, Ieval, true).
seq([E], Bs0, Ieval) ->
case dbg_icmd:cmd(E, Bs0, Ieval) of
@@ -1013,7 +1021,7 @@ safe_bif(M, F, As, Bs, Ieval) ->
{value,Value,Bs}
catch
Class:Reason ->
- exception(Class, Reason, Bs, Ieval)
+ exception(Class, Reason, Bs, Ieval, true)
end.
eval_send(To, Msg, Bs, Ieval) ->
diff --git a/lib/debugger/src/dbg_istk.erl b/lib/debugger/src/dbg_istk.erl
index 2c4c2a3518..34070aa8f2 100644
--- a/lib/debugger/src/dbg_istk.erl
+++ b/lib/debugger/src/dbg_istk.erl
@@ -19,7 +19,7 @@
-module(dbg_istk).
-export([init/0,to_external/0,from_external/1,
push/2,pop/0,pop/1,stack_level/0,
- delayed_stacktrace/0,delayed_stacktrace/1,
+ delayed_stacktrace/0,delayed_stacktrace/2,
bindings/1,stack_frame/2,backtrace/2,
in_use_p/2]).
@@ -107,60 +107,55 @@ stack_level([]) -> 1;
stack_level([#e{level=Le}|_]) -> Le.
%% delayed_stacktrace() -> CreateStacktraceFun
-%% delayed_stacktrace(#ieval{}) -> CreateStacktraceFun
+%% delayed_stacktrace(ArgFlag, #ieval{}) -> CreateStacktraceFun
+%% ArgFlag = no_args | include_args
%% CreateStacktraceFun = fun(NumberOfEntries)
%%
%% Return a fun that can convert the internal stack format to
%% an imitation of the regular stacktrace.
-%%
-%% Max three elements, no repeated (recursive) calls to the same
-%% function and convert argument lists to arity for all but the topmost
-%% entry (and funs).
delayed_stacktrace() ->
- Stack = get(?STACK),
- do_delayed_stacktrace(Stack).
+ Stack0 = get(?STACK),
+ fun(NumEntries) ->
+ Stack = stacktrace(NumEntries, Stack0, []),
+ [ArityOnly || {ArityOnly,_} <- Stack]
+ end.
-delayed_stacktrace(Ieval) ->
+delayed_stacktrace(include_args, Ieval) ->
#ieval{module=Mod,function=Name,arguments=As} = Ieval,
- Stack = [#e{mfa={Mod,Name,As}}|get(?STACK)],
- do_delayed_stacktrace(Stack).
-
-do_delayed_stacktrace(Stack) ->
- fun(_NumEntries) ->
- fix_stacktrace(Stack)
+ Stack0 = [#e{mfa={Mod,Name,As}}|get(?STACK)],
+ fun(NumEntries) ->
+ case stacktrace(NumEntries, Stack0, []) of
+ [] ->
+ [];
+ [{_,WithArgs}|Stack] ->
+ [WithArgs | [ArityOnly || {ArityOnly,_} <- Stack]]
+ end
+ end;
+delayed_stacktrace(no_args, Ieval) ->
+ #ieval{module=Mod,function=Name,arguments=As} = Ieval,
+ Stack0 = [#e{mfa={Mod,Name,As}}|get(?STACK)],
+ fun(NumEntries) ->
+ Stack = stacktrace(NumEntries, Stack0, []),
+ [ArityOnly || {ArityOnly,_} <- Stack]
end.
-fix_stacktrace(Stack) ->
- case fix_stacktrace2(sublist(Stack, 1, 3)) of
- [] ->
- [];
- [H|T] ->
- [H|args2arity(T)]
- end.
+stacktrace(N, [E|T], []) ->
+ stacktrace(N-1, T, [normalize(E)]);
+stacktrace(N, [E|T], [{P,_}|_]=Acc) when N > 0 ->
+ case normalize(E) of
+ {P,_} ->
+ stacktrace(N, T, Acc);
+ New ->
+ stacktrace(N-1, T, [New|Acc])
+ end;
+stacktrace(_, _, Acc) ->
+ lists:reverse(Acc).
-sublist([], _Start, _Length) ->
- []; % workaround, lists:sublist([],2,3) fails
-sublist(L, Start, Length) ->
- lists:sublist(L, Start, Length).
-
-fix_stacktrace2([#e{mfa={M,F,As1}}, #e{mfa={M,F,As2}}|_])
- when length(As1) =:= length(As2) ->
- [{M,F,As1}];
-fix_stacktrace2([#e{mfa={Fun,As1}}, #e{mfa={Fun,As2}}|_])
- when length(As1) =:= length(As2) ->
- [{Fun,As1}];
-fix_stacktrace2([#e{mfa=MFA}|Entries]) ->
- [MFA|fix_stacktrace2(Entries)];
-fix_stacktrace2([]) ->
- [].
-
-args2arity([{M,F,As}|Entries]) when is_list(As) ->
- [{M,F,length(As)}|args2arity(Entries)];
-args2arity([Entry|Entries]) ->
- [Entry|args2arity(Entries)];
-args2arity([]) ->
- [].
+normalize(#e{mfa={_,Fun,As}}) when is_function(Fun) ->
+ {{Fun,length(As)},{Fun,As}};
+normalize(#e{mfa={M,F,As}}) ->
+ {{M,F,length(As)},{M,F,As}}.
%% bindings(SP) -> Bs
%% SP = Le % stack pointer