1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(error_handler). 21 22%% See the comment before the int/0 function for an explanation 23%% why this option is needed. 24-compile(no_module_opt). 25 26%% Callbacks called from the run-time system. 27-export([undefined_function/3,undefined_lambda/3,breakpoint/3]). 28 29%% Exported utility functions. 30-export([raise_undef_exception/3]). 31-export([stub_function/3]). 32 33-spec undefined_function(Module, Function, Args) -> 34 any() when 35 Module :: atom(), 36 Function :: atom(), 37 Args :: list(). 38 39undefined_function(Module, Func, Args) -> 40 case ensure_loaded(Module) of 41 {module, Module} -> 42 case erlang:function_exported(Module, Func, length(Args)) of 43 true -> 44 apply(Module, Func, Args); 45 false -> 46 call_undefined_function_handler(Module, Func, Args) 47 end; 48 {module, _} -> 49 crash(Module, Func, Args); 50 _Other -> 51 crash(Module, Func, Args) 52 end. 53 54-spec undefined_lambda(Module, Fun, Args) -> term() when 55 Module :: atom(), 56 Fun :: fun(), 57 Args :: list(). 58 59undefined_lambda(Module, Fun, Args) -> 60 case ensure_loaded(Module) of 61 {module, Module} -> 62 %% There is no need (and no way) to test if the fun is present. 63 %% apply/2 will not call us again if the fun is missing. 64 apply(Fun, Args); 65 {module, _} -> 66 crash(Fun, Args); 67 _Other -> 68 crash(Fun, Args) 69 end. 70 71-spec breakpoint(Module :: atom(), Function :: atom(), Args :: [_]) -> 72 any(). 73 74breakpoint(Module, Func, Args) -> 75 (int()):eval(Module, Func, Args). 76 77-spec raise_undef_exception(Module, Function, Args) -> no_return() when 78 Module :: atom(), 79 Function :: atom(), 80 Args :: list(). 81 82raise_undef_exception(Module, Func, Args) -> 83 crash({Module,Func,Args,[]}). 84 85%% Used to make the call to the 'int' module a "weak" one, to avoid 86%% making Kernel a visible dependency to Debugger in xref. (To ensure 87%% that the call in breakpoint/3 is kept as an apply to an unknown 88%% module, this module must be compiled with the 'no_module_opt' 89%% option to turn off inter-function type analysis.) 90 91int() -> int. 92 93%% 94%% Crash providing a beautiful stack backtrace. 95%% 96-spec crash(atom(), [term()]) -> no_return(). 97 98crash(Fun, Args) -> 99 crash({Fun,Args,[]}). 100 101-spec crash(atom(), atom(), arity() | [term()]) -> no_return(). 102 103crash(M, F, A) -> 104 crash({M,F,A,[]}). 105 106-spec crash(tuple()) -> no_return(). 107 108crash(Tuple) -> 109 try erlang:error(undef) 110 catch 111 error:undef:Stacktrace -> 112 Stk = [Tuple|tl(Stacktrace)], 113 erlang:raise(error, undef, Stk) 114 end. 115 116%% If the code_server has not been started yet dynamic code loading 117%% is handled by init. 118ensure_loaded(Module) -> 119 Self = self(), 120 case whereis(code_server) of 121 %% Perhaps double fault should be detected in code:ensure_loaded/1 122 %% instead, since this error handler cannot know whether the 123 %% code server can resolve the problem or not. 124 %% An {error, Reason} return from there would crash the code server and 125 %% bring down the node. 126 Self -> 127 Error = "The code server called the unloaded module `" ++ 128 atom_to_list(Module) ++ "'", 129 halt(Error); 130 Pid when is_pid(Pid) -> 131 code:ensure_loaded(Module); 132 _ -> 133 init:ensure_loaded(Module) 134 end. 135 136-spec stub_function(atom(), atom(), [_]) -> no_return(). 137 138stub_function(Mod, Func, Args) -> 139 exit({undef,[{Mod,Func,Args,[]}]}). 140 141call_undefined_function_handler(Module, Func, Args) -> 142 Handler = '$handle_undefined_function', 143 case erlang:function_exported(Module, Handler, 2) of 144 false -> 145 crash(Module, Func, Args); 146 true -> 147 Module:Handler(Func, Args) 148 end. 149