831
869
#define BsSkipBitsImm(Bits, Fail) \
833
size_t new_offset = erts_mb.offset + (Bits); \
871
size_t new_offset = erts_mb.offset + (Bits); \
834
872
if (new_offset <= erts_mb.size) { erts_mb.offset = new_offset; } \
839
#define BsPutIntegerImm(Sz, Flags, Src) \
841
if (!erts_bs_put_integer((Src), (Sz), (Flags))) { goto badarg; } \
878
#define BsStartMatch2(Src, Live, Max, Dst, Store, Fail) \
880
Eterm _result; Uint _wordsneeded; \
881
_wordsneeded = ERL_BIN_MATCHSTATE_SIZE(Max); \
882
TestHeap(_wordsneeded, Live); \
884
_result = erts_bs_start_match_2(c_p, Src, Max); \
885
HTOP = HEAP_TOP(c_p); \
886
if (is_non_value(_result)) { Fail; } \
887
else { Store(_result, Dst); } \
890
#define BsGetInteger2_8(Ms, Dst, Store, Fail) \
892
ErlBinMatchBuffer *_mb; \
894
_mb = ms_matchbuffer(Ms); \
895
if (_mb->size - _mb->offset < 8) { Fail; } \
896
if ((_mb->offset & 7) != 0) { \
897
_result = erts_bs_get_integer_2(c_p, 8, 0, _mb); \
900
_result = make_small(_mb->base[_mb->offset/8]); \
903
Store(_result, Dst); \
906
#define BsGetInteger2_16(Ms, Dst, Store, Fail) \
908
ErlBinMatchBuffer *_mb; \
910
_mb = ms_matchbuffer(Ms); \
911
if (_mb->size - _mb->offset < 16) { Fail; } \
912
if ((_mb->offset & 7) != 0) { \
913
_result = erts_bs_get_integer_2(c_p, 16, 0, _mb); \
916
_result = make_small(get_int16(_mb->base + _mb->offset/8)); \
919
Store(_result, Dst); \
922
#define BsGetInteger2_32(Ms, Live, Dst, Store, Fail) \
924
ErlBinMatchBuffer *_mb; \
927
_mb = ms_matchbuffer(Ms); \
928
if (_mb->size - _mb->offset < 32) { Fail; } \
929
if ((_mb->offset & 7) != 0) { \
930
_result = erts_bs_get_integer_2(c_p, 32, 0, _mb); \
933
_integer = get_int32(_mb->base + _mb->offset/8); \
935
if (IS_USMALL(0, _integer)) { \
936
_result = make_small(_integer); \
938
TestHeap(BIG_UINT_HEAP_SIZE, Live); \
939
_result = uint_to_big((Uint) _integer, HTOP); \
940
HTOP += BIG_UINT_HEAP_SIZE; \
943
Store(_result, Dst); \
946
#define BsGetIntegerImm2(Ms, Live, Sz, Flags, Dst, Store, Fail) \
948
ErlBinMatchBuffer *_mb; \
949
Eterm _result; unsigned wordneed; \
951
wordneed = 1+WSIZE(NBYTES(Sz)); \
952
TestHeap(wordneed, Live); \
954
_mb = ms_matchbuffer(Ms); \
956
_result = erts_bs_get_integer_2(c_p, (Sz), (Flags), _mb); \
957
HTOP = HEAP_TOP(c_p); \
958
if (is_non_value(_result)) { Fail; } \
959
else { Store(_result, Dst); } \
962
#define BsGetInteger2(Ms, Live, Sz, Flags, Dst, Store, Fail) \
964
ErlBinMatchBuffer *_mb; \
965
Eterm _result; Sint _size; unsigned wordneed; \
966
if (!is_small(Sz) || (_size = signed_val(Sz)) < 0) { Fail; } \
967
_size *= ((Flags) >> 3); \
968
wordneed = 1+WSIZE(NBYTES(_size)); \
969
TestHeap(wordneed, Live); \
970
_mb = ms_matchbuffer(Ms); \
972
_result = erts_bs_get_integer_2(c_p, _size, (Flags), _mb); \
973
HTOP = HEAP_TOP(c_p); \
974
if (is_non_value(_result)) { Fail; } \
975
else { Store(_result, Dst); } \
978
#define BsGetFloat2(Ms, Live, Sz, Flags, Dst, Store, Fail) \
980
ErlBinMatchBuffer *_mb; \
981
Eterm _result; Sint _size; \
982
if (!is_small(Sz) || (_size = signed_val(Sz)) < 0) { Fail; } \
983
_size *= ((Flags) >> 3); \
984
TestHeap(FLOAT_SIZE_OBJECT, Live); \
985
_mb = ms_matchbuffer(Ms); \
987
_result = erts_bs_get_float_2(c_p, _size, (Flags), _mb); \
988
HTOP = HEAP_TOP(c_p); \
989
if (is_non_value(_result)) { Fail; } \
990
else { Store(_result, Dst); } \
993
#define BsGetBinaryImm_2(Ms, Live, Sz, Flags, Dst, Store, Fail) \
995
ErlBinMatchBuffer *_mb; \
997
TestHeap(heap_bin_size(ERL_ONHEAP_BIN_LIMIT), Live); \
998
_mb = ms_matchbuffer(Ms); \
1000
_result = erts_bs_get_binary_2(c_p, (Sz), (Flags), _mb); \
1001
HTOP = HEAP_TOP(c_p); \
1002
if (is_non_value(_result)) { Fail; } \
1003
else { Store(_result, Dst); } \
1006
#define BsGetBinary_2(Ms, Live, Sz, Flags, Dst, Store, Fail) \
1008
ErlBinMatchBuffer *_mb; \
1009
Eterm _result; Sint _size; \
1010
if (!is_small(Sz) || (_size = signed_val(Sz)) < 0) { Fail; } \
1011
TestHeap(heap_bin_size(ERL_ONHEAP_BIN_LIMIT), Live); \
1012
_size *= ((Flags) >> 3); \
1013
TestHeap(heap_bin_size(ERL_ONHEAP_BIN_LIMIT), Live); \
1014
_mb = ms_matchbuffer(Ms); \
1016
_result = erts_bs_get_binary_2(c_p, _size, (Flags), _mb); \
1017
HTOP = HEAP_TOP(c_p); \
1018
if (is_non_value(_result)) { Fail; } \
1019
else { Store(_result, Dst); } \
1022
#define BsGetBinaryAll_2(Ms, Live, Unit, Dst, Store, Fail) \
1024
ErlBinMatchBuffer *_mb; \
1026
TestHeap(ERL_SUB_BIN_SIZE, Live); \
1027
_mb = ms_matchbuffer(Ms); \
1028
if (((_mb->size - _mb->offset) % Unit) == 0) \
1030
_result = erts_bs_get_binary_all_2(c_p, _mb); \
1031
HTOP = HEAP_TOP(c_p); \
1032
if (is_non_value(_result)) { Fail; } \
1033
else { Store(_result, Dst); } \
1038
#define BsSkipBits2(Ms, Bits, Unit, Fail) \
1040
ErlBinMatchBuffer *_mb; \
1041
size_t new_offset; Sint _size; \
1042
_mb = ms_matchbuffer(Ms); \
1043
if (!is_small(Bits) || (_size = signed_val(Bits)) < 0) { Fail; } \
1044
new_offset = _mb->offset + _size * (Unit); \
1045
if (new_offset <= _mb->size) { _mb->offset = new_offset; } \
1049
#define BsSkipBitsAll2(Ms, Unit, Fail) \
1051
ErlBinMatchBuffer *_mb; \
1052
_mb = ms_matchbuffer(Ms); \
1053
if (((_mb->size - _mb->offset) % Unit) == 0) {_mb->offset = _mb->size; } \
1057
#define BsSkipBitsImm2(Ms, Bits, Fail) \
1059
ErlBinMatchBuffer *_mb; \
1060
size_t new_offset; \
1061
_mb = ms_matchbuffer(Ms); \
1062
new_offset = _mb->offset + (Bits); \
1063
if (new_offset <= _mb->size) { _mb->offset = new_offset; } \
1067
#define NewBsPutIntegerImm(Sz, Flags, Src) \
1069
if (!erts_new_bs_put_integer(ERL_BITS_ARGS_3((Src), (Sz), (Flags)))) { goto badarg; } \
1072
#define NewBsPutInteger(Sz, Flags, Src) \
1074
Sint _size = signed_val(Sz) * ((Flags) >> 3); \
1075
if (!erts_new_bs_put_integer(ERL_BITS_ARGS_3((Src), _size, (Flags)))) { goto badarg; } \
1078
#define NewBsPutFloatImm(Sz, Flags, Src) \
1080
if (!erts_new_bs_put_float(c_p, (Src), (Sz), (Flags))) { goto badarg; } \
1083
#define NewBsPutFloat(Sz, Flags, Src) \
1085
Sint _size = signed_val(Sz) * ((Flags) >> 3); \
1086
if (!erts_new_bs_put_float(c_p, (Src), _size, (Flags))) { goto badarg; } \
1089
#define NewBsPutBinary(Sz, Flags, Src) \
1091
Sint _size = signed_val(Sz) * ((Flags) >> 3); \
1092
if (!erts_new_bs_put_binary(ERL_BITS_ARGS_2((Src), _size))) { goto badarg; } \
1095
#define NewBsPutBinaryImm(Sz, Src) \
1097
if (!erts_new_bs_put_binary(ERL_BITS_ARGS_2((Src), (Sz)))) { goto badarg; } \
1100
#define NewBsPutBinaryAll(Src) \
1102
if (!erts_new_bs_put_binary_all(ERL_BITS_ARGS_1((Src)))) { goto badarg; } \
1106
* Macros for old instruction set for constructing binaries.
1109
#if !defined(HEAP_FRAG_ELIM_TEST)
844
1111
#define BsPutInteger(Sz, Flags, Src) \
847
1114
if (!is_small(Sz) || (_size = signed_val(Sz)) < 0) { goto badarg; } \
848
1115
_size *= ((Flags) >> 3); \
849
if (!erts_bs_put_integer((Src), _size, (Flags))) { goto badarg; } \
852
#define BsPutFloatImm(Sz, Flags, Src) \
854
if (!erts_bs_put_float((Src), (Sz), (Flags))) { goto badarg; } \
1116
if (!erts_bs_put_integer(ERL_BITS_ARGS_3((Src), _size, (Flags)))) { goto badarg; } \
857
1119
#define BsPutFloat(Sz, Flags, Src) \
860
1122
if (!is_small(Sz) || (_size = signed_val(Sz)) < 0) { goto badarg; } \
861
1123
_size *= ((Flags) >> 3); \
862
if (!erts_bs_put_float((Src), _size, (Flags))) { goto badarg; } \
1124
if (!erts_bs_put_float(c_p, (Src), _size, (Flags))) { goto badarg; } \
865
1127
#define BsPutBinary(Sz, Flags, Src) \
868
1130
if (!is_small(Sz) || (_size = signed_val(Sz)) < 0) { goto badarg; } \
869
1131
_size *= ((Flags) >> 3); \
870
if (!erts_bs_put_binary((Src), _size)) { goto badarg; } \
873
#define BsPutBinaryImm(Sz, Src) \
875
if (!erts_bs_put_binary((Src), (Sz))) { goto badarg; } \
878
#define BsPutBinaryAll(Src) \
880
if (!erts_bs_put_binary_all((Src))) { goto badarg; } \
1132
if (!erts_bs_put_binary(ERL_BITS_ARGS_2((Src), _size))) { goto badarg; } \
1135
#define BsPutBinaryAll(Src) \
1137
if (!erts_bs_put_binary_all(ERL_BITS_ARGS_1((Src)))) { goto badarg; } \
884
1142
#define IsPort(Src, Fail) if (is_not_port(Src)) { Fail; }
885
1143
#define IsPid(Src, Fail) if (is_not_pid(Src)) { Fail; }
886
1144
#define IsRef(Src, Fail) if (is_not_ref(Src)) { Fail; }
1146
#if defined(HEAP_FRAG_ELIM_TEST)
1147
static BifFunction translate_gc_bif(void* gcf);
888
1149
static Eterm* handle_error(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf);
1150
static Eterm* next_catch(Process* c_p, Eterm *reg);
1151
static void terminate_proc(Process* c_p, Eterm Value);
1152
static Eterm add_stacktrace(Process* c_p, Eterm Value, Eterm exc);
1153
static void save_stacktrace(Process* c_p, Eterm* pc, Eterm* reg,
1154
BifFunction bf, Eterm args);
1155
static struct StackTrace * get_trace_from_exc(Eterm exc);
1156
static Eterm make_arglist(Process* c_p, Eterm* reg, int a);
889
1157
static Eterm call_error_handler(Process* p, Eterm* ip, Eterm* reg);
890
1158
static Eterm call_breakpoint_handler(Process* p, Eterm* fi, Eterm* reg);
1159
static Uint* fixed_apply(Process* p, Eterm* reg, Uint arity);
891
1160
static Eterm* apply(Process* p, Eterm module, Eterm function,
892
1161
Eterm args, Eterm* reg);
893
1162
static int hibernate(Process* c_p, Eterm module, Eterm function,
3558
4590
am_try_clause, /* 16 */
4594
* To fully understand the error handling, one must keep in mind that
4595
* when an exception is thrown, the search for a handler can jump back
4596
* and forth between Beam and native code. Upon each mode switch, a
4597
* dummy handler is inserted so that if an exception reaches that point,
4598
* the handler is invoked (like any handler) and transfers control so
4599
* that the search for a real handler is continued in the other mode.
4600
* Therefore, c_p->freason and c_p->fvalue must still hold the exception
4601
* info when the handler is executed, but normalized so that creation of
4602
* error terms and saving of the stack trace is only done once, even if
4603
* we pass through the error handling code several times.
4605
* When a new exception is raised, the current stack trace information
4606
* is quick-saved in a small structure allocated on the heap. Depending
4607
* on how the exception is eventually caught (perhaps by causing the
4608
* current process to terminate), the saved information may be used to
4609
* create a symbolic (human-readable) representation of the stack trace
4610
* at the point of the original exception.
3562
4614
handle_error(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf)
3564
Eterm temp_current[3];
3568
int max_depth = erts_backtrace_depth;
3571
* For most exceptions, the error reason will look like {Value,Where},
3572
* where Where is a list.
3573
* Where will not be used for exit/1 and throw/1.
3578
Eterm* next_p = &Where;
3579
/* Where to store the next element of Where. */
3580
Eterm *save_current = c_p->current;
3581
/* Needed when bif traps throws exceptions */
3582
c_p->i = pc; /* In case we call erl_exit(). */
3585
* First, make sure that we know the {M,F,A} of the current function.
3588
if (pc != NULL && (c_p->current = find_function_from_pc(pc)) == NULL) {
3590
* Default to the initial function (e.g. spawn_link(erlang, abs, [1])).
3592
c_p->current = c_p->initial;
3593
if (beam_debug_apply <= pc && pc < beam_debug_apply+beam_debug_apply_size) {
3594
Eterm* y0 = c_p->stop+1;
3596
if (is_tuple(*y0)) {
3597
Eterm* tp = tuple_val(*y0);
3599
if (arityval(tp[0]) == 3) {
3602
temp_current[0] = tp[1];
3603
temp_current[1] = tp[2];
3604
if ((arity = list_length(tp[3])) >= 0) {
3605
temp_current[2] = (Eterm) arity;
3606
c_p->current = temp_current;
3610
if (c_p->freason & EXF_ARGLIST) {
3611
c_p->freason -= EXF_ARGLIST;
3618
* We are not allowed to have backwards pointers between heap fragments
3619
* or from a heap fragment to the heap. Therefore, we must allocate all
3620
* storage we need in a single block.
3623
needed = 3+3+6+6+2*3;
3624
if (c_p->current != NULL) {
3625
needed += c_p->current[2]*2;
3627
needed += 4+2+6+6*max_depth+3;
3628
heap_start = hp = HAlloc(c_p, needed);
3631
* Retrieve the atom to use in Value.
4617
Eterm Value = c_p->fvalue;
4618
Eterm Args = am_true;
4619
c_p->i = pc; /* In case we call erl_exit(). */
3634
4621
ASSERT(c_p->freason != TRAP); /* Should have been handled earlier. */
3635
4622
ASSERT(c_p->freason != RESCHEDULE); /* Should have been handled earlier. */
3636
{ Uint r = GET_EXC_INDEX(c_p->freason);
3637
ASSERT(r < NUMBER_EXIT_CODES); /* range check */
3638
if (r < NUMBER_EXIT_CODES) {
3639
Value = error_atom[r];
3641
Value = am_internal_error;
3642
c_p->freason = EXC_INTERNAL_ERROR;
3647
* Throws that are not caught are turned into 'nocatch' errors.
4625
* Check if we have an arglist for the top level call. If so, this
4626
* is encoded in Value, so we have to dig out the real Value as well
4629
if (c_p->freason & EXF_ARGLIST) {
4631
ASSERT(is_tuple(Value));
4632
tp = tuple_val(Value);
4638
* Save the stack trace info if the EXF_SAVETRACE flag is set. The
4639
* main reason for doing this separately is to allow throws to later
4640
* become promoted to errors without losing the original stack
4641
* trace, even if they have passed through one or more catch and
4642
* rethrow. It also makes the creation of symbolic stack traces much
4645
if (c_p->freason & EXF_SAVETRACE) {
4646
save_stacktrace(c_p, pc, reg, bf, Args);
4650
* Throws that are not caught are turned into 'nocatch' errors
3650
4652
if ((c_p->freason & EXF_THROWN) && (c_p->catches <= 0) ) {
3651
c_p->fvalue = TUPLE2(hp, am_nocatch, c_p->fvalue);
3653
c_p->freason = EXC_USER_ERROR; /* force stack trace and log */
4653
hp = HAlloc(c_p, 3);
4654
Value = TUPLE2(hp, am_nocatch, Value);
4655
c_p->freason = EXC_ERROR;
4658
/* Get the fully expanded error term */
4659
Value = expand_error_value(c_p, c_p->freason, Value);
4661
/* Save final error term and stabilize the exception flags so no
4662
further expansion is done. */
4663
c_p->fvalue = Value;
4664
c_p->freason = PRIMARY_EXCEPTION(c_p->freason);
4666
/* Find a handler or die */
4667
if ((c_p->catches > 0 || IS_TRACED_FL(c_p, F_EXCEPTION_TRACE))
4668
&& !(c_p->freason & EXF_PANIC)) {
4670
/* The Beam handler code (catch_end or try_end) checks reg[0]
4671
for THE_NON_VALUE to see if the previous code finished
4672
abnormally. If so, reg[1], reg[2] and reg[3] should hold the
4673
exception class, term and trace, respectively. (If the
4674
handler is just a trap to native code, these registers will
4676
reg[0] = THE_NON_VALUE;
4677
reg[1] = exception_tag[GET_EXC_CLASS(c_p->freason)];
4679
reg[3] = c_p->ftrace;
4680
if ( (new_pc = next_catch(c_p, reg))) return new_pc;
4681
if (c_p->catches > 0) erl_exit(1, "Catch not found");
4683
terminate_proc(c_p, Value);
4688
* Find the nearest catch handler
4691
next_catch(Process* c_p, Eterm *reg) {
4692
int active_catches = c_p->catches > 0;
4693
int have_return_to_trace = 0;
4694
Eterm *ptr, *prev, *return_to_trace_ptr = NULL;
4695
Uint i_return_trace = beam_return_trace[0];
4696
Uint i_return_to_trace = beam_return_to_trace[0];
4697
ptr = prev = c_p->stop;
4698
ASSERT(is_CP(*ptr));
4699
ASSERT(ptr <= STACK_START(c_p));
4700
if (ptr == STACK_START(c_p)) return NULL;
4701
if ((is_not_CP(*ptr) || (*cp_val(*ptr) != i_return_trace &&
4702
*cp_val(*ptr) != i_return_to_trace))
4704
/* Can not follow cp here - code may be unloaded */
4705
Uint *cpp = cp_val((Eterm) c_p->cp);
4706
if (cpp == beam_exception_trace) {
4707
erts_trace_exception(c_p, (Eterm*) ptr[0],
4708
reg[1], reg[2], ptr+1);
4709
/* Skip return_trace parameters */
4711
} else if (cpp == beam_return_trace) {
4712
/* Skip return_trace parameters */
4714
} else if (cpp == beam_return_to_trace) {
4715
have_return_to_trace = !0; /* Record next cp */
4718
while (ptr < STACK_START(c_p)) {
4719
if (is_catch(*ptr)) {
4720
if (active_catches) goto found_catch;
4723
else if (is_CP(*ptr)) {
4725
if (*cp_val(*prev) == i_return_trace) {
4726
/* Skip stack frame variables */
4727
while (++ptr, ptr < STACK_START(c_p) && is_not_CP(*ptr)) {
4728
if (is_catch(*ptr) && active_catches) goto found_catch;
4730
if (cp_val(*prev) == beam_exception_trace) {
4731
erts_trace_exception(c_p, (Eterm*) ptr[0],
4732
reg[1], reg[2], ptr+1);
4734
/* Skip return_trace parameters */
4736
} else if (*cp_val(*prev) == i_return_to_trace) {
4737
/* Skip stack frame variables */
4738
while (++ptr, ptr < STACK_START(c_p) && is_not_CP(*ptr)) {
4739
if (is_catch(*ptr) && active_catches) goto found_catch;
4741
have_return_to_trace = !0; /* Record next cp */
4742
return_to_trace_ptr = NULL;
4744
if (have_return_to_trace) {
4745
/* Record this cp as possible return_to trace cp */
4746
have_return_to_trace = 0;
4747
return_to_trace_ptr = ptr;
4748
} else return_to_trace_ptr = NULL;
4756
ASSERT(ptr < STACK_START(c_p));
4758
if (IS_TRACED_FL(c_p, F_TRACE_RETURN_TO) && return_to_trace_ptr) {
4759
/* The stackframe closest to the catch contained an
4760
* return_to_trace entry, so since the execution now
4761
* continues after the catch, a return_to trace message
4762
* would be appropriate.
4764
erts_trace_return_to(c_p, cp_val(*return_to_trace_ptr));
4766
return catch_pc(*ptr);
4770
* Terminating the process when an exception is not caught
4773
terminate_proc(Process* c_p, Eterm Value)
4775
/* Add a stacktrace if this is an error. */
4776
if (GET_EXC_CLASS(c_p->freason) == EXTAG_ERROR) {
4777
Value = add_stacktrace(c_p, Value, c_p->ftrace);
4779
/* EXF_LOG is a primary exception flag */
4780
if (c_p->freason & EXF_LOG) {
4781
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
4782
erts_dsprintf(dsbufp, "Error in process %T ", c_p->id);
4783
if (erts_is_alive())
4784
erts_dsprintf(dsbufp, "on node %T ", erts_this_node->sysname);
4785
erts_dsprintf(dsbufp,"with exit value: %0.*T\n", display_items, Value);
4786
erts_send_error_to_logger(c_p->group_leader, dsbufp);
3657
* Make sure we form the correct error value
4789
* If we use a shared heap, the process will be garbage-collected.
4790
* Must zero c_p->arity to indicate that there are no live registers.
3660
switch (GET_EXC_INDEX(c_p->freason)) {
4793
erts_do_exit_process(c_p, Value);
4797
* Build and add a symbolic stack trace to the error value.
4800
add_stacktrace(Process* c_p, Eterm Value, Eterm exc) {
4801
Eterm Where = build_stacktrace(c_p, exc);
4802
Eterm* hp = HAlloc(c_p, 3);
4803
return TUPLE2(hp, Value, Where);
4807
* Forming the correct error value from the internal error code.
4808
* This does not update c_p->fvalue or c_p->freason.
4811
expand_error_value(Process* c_p, Uint freason, Eterm Value) {
4815
r = GET_EXC_INDEX(freason);
4816
ASSERT(r < NUMBER_EXIT_CODES); /* range check */
4817
ASSERT(is_value(Value));
3661
4820
case (GET_EXC_INDEX(EXC_PRIMARY)):
3662
/* Primary exceptions use fvalue directly */
3663
ASSERT(is_value(c_p->fvalue));
3664
Value = c_p->fvalue;
4821
/* Primary exceptions use fvalue as it is */
3666
4823
case (GET_EXC_INDEX(EXC_BADMATCH)):
3667
4824
case (GET_EXC_INDEX(EXC_CASE_CLAUSE)):
3668
4825
case (GET_EXC_INDEX(EXC_TRY_CLAUSE)):
3669
4826
case (GET_EXC_INDEX(EXC_BADFUN)):
3670
ASSERT(is_value(c_p->fvalue));
3671
Value = TUPLE2(hp, Value, c_p->fvalue);
3674
4827
case (GET_EXC_INDEX(EXC_BADARITY)):
3675
ASSERT(is_value(c_p->fvalue));
3676
ASSERT(*next_p == NIL);
3677
*next_p = CONS(hp, c_p->fvalue, NIL);
4828
/* Some common exceptions: value -> {atom, value} */
4829
ASSERT(is_value(Value));
4830
hp = HAlloc(c_p, 3);
4831
Value = TUPLE2(hp, error_atom[r], Value);
4834
/* Other exceptions just use an atom as descriptor */
4835
Value = error_atom[r];
3684
4839
ASSERT(Value != am_internal_error);
4845
* Quick-saving the stack trace in an internal form on the heap. Note
4846
* that c_p->ftrace will point to a cons cell which holds the given args
4847
* and the saved data (encoded as a bignum).
4849
* (It would be much better to put the arglist - when it exists - in the
4850
* error value instead of in the actual trace; e.g. '{badarg, Args}'
4851
* instead of using 'badarg' with Args in the trace. The arglist may
4852
* contain very large values, and right now they will be kept alive as
4853
* long as the stack trace is live. Preferably, the stack trace should
4854
* always be small, so that it does not matter if it is long-lived.
4855
* However, it is probably not possible to ever change the format of
4860
save_stacktrace(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf,
4862
struct StackTrace* s;
4864
int depth = erts_backtrace_depth; /* max depth (never negative) */
4866
/* There will always be a current function */
4870
/* Create a container for the exception data */
4871
sz = (offsetof(struct StackTrace, trace) + sizeof(Eterm)*depth
4872
+ sizeof(Eterm) - 1) / sizeof(Eterm);
4873
s = (struct StackTrace *) HAlloc(c_p, 1 + sz);
4874
/* The following fields are inside the bignum */
4875
s->header = make_pos_bignum_header(sz);
4876
s->freason = c_p->freason;
3688
* Build the Where part of the reason (the backtrace), if the
3689
* EXF_TRACE flag is set.
4880
* If the failure was in a BIF other than 'error', 'exit' or
4881
* 'throw', find the bif-table index and save the argument
4882
* registers by consing up an arglist.
3692
if (c_p->freason & EXF_TRACE) {
3696
Uint* prev = NULL; /* Pointer to func_info for previous function
3701
* Check if we have an arglist term to use instead of the arity
3702
* for the top level call. (If so, this is encoded in Value.)
3705
if (c_p->freason & EXF_ARGLIST) {
3708
ASSERT(is_tuple(Value));
3709
prev = c_p->current;
3710
ASSERT(prev != NULL);
3711
tp = tuple_val(Value);
3713
mfa = TUPLE3(hp, prev[0], prev[1], tp[2]);
3715
ASSERT(*next_p == NIL);
3716
*next_p = CONS(hp, mfa, NIL);
3723
* If the failure was in a BIF, this is the first element in Where.
3724
* If the failure was caused by 'fault' or 'throw', we won't show it.
3727
if (bf != NULL && bf != fault_1 && bf != fault_2 && bf != throw_1) {
3730
for (i = 0; i < BIF_SIZE; i++) {
3731
if (bf == bif_table[i].f || bf == bif_table[i].traced) {
3732
int arity = bif_table[i].arity;
3736
/* hp += 6+2*arity */
3738
args = CONS(hp, reg[arity-1], args);
3742
mfa = TUPLE3(hp, bif_table[i].module, bif_table[i].name, args);
3744
ASSERT(*next_p == NIL);
3745
*next_p = CONS(hp, mfa, NIL);
3751
if (i >= BIF_SIZE) {
3753
* The Bif does not really exist (no BIF entry).
3754
* It is a TRAP and traps are called through
3755
* apply_bif, which also sets c_p->current (luckily).
3756
* We save c_p->current at the beginning of this function
3757
* so that we can dig out {M,F,Args} from that.
3760
int arity = save_current[2];
3762
ASSERT(is_atom(save_current[0]) && is_atom(save_current[1]) &&
3763
save_current[2] <= 3);
3766
/* hp += 6+2*arity */
3769
args = CONS(hp, reg[arity-1], args);
3773
mfa = TUPLE3(hp, save_current[0], save_current[1], args);
3775
ASSERT(*next_p == NIL);
3776
*next_p = CONS(hp, mfa, NIL);
3783
* Add the {M,F,A} for the current function,
3784
* where A is arity or arguments.
3787
if (c_p->current != prev) {
3788
Eterm a; /* Arguments or arity. */
3789
prev = c_p->current;
3790
if (c_p->current == c_p->stop) {
3794
if ( (GET_EXC_INDEX(c_p->freason)) !=
3795
(GET_EXC_INDEX(EXC_FUNCTION_CLAUSE)) ) {
3796
a = make_small(prev[2]);
4884
if (bf != NULL && bf != error_1 && bf != error_2
4885
&& bf != fault_1 && bf != fault_2
4886
&& bf != exit_1 && bf != throw_1) {
4889
for (i = 0; i < BIF_SIZE; i++) {
4890
if (bf == bif_table[i].f || bf == bif_table[i].traced) {
4891
Export *ep = bif_export[i];
4892
s->current = ep->code;
4893
a = bif_table[i].arity;
4897
if (i >= BIF_SIZE) {
4899
* The Bif does not really exist (no BIF entry). It is a
4900
* TRAP and traps are called through apply_bif, which also
4901
* sets c_p->current (luckily).
4903
ASSERT(c_p->current);
4904
s->current = c_p->current;
4906
ASSERT(s->current[2] <= 3);
4908
/* Save first stack entry */
4911
s->trace[s->depth++] = pc;
4915
args = make_arglist(c_p, reg, a); /* Overwrite CAR(c_p->ftrace) */
4917
s->current = c_p->current;
4919
* For a function_clause error, the arguments are in the beam
4920
* registers, c_p->cp is valid, and c_p->current is set.
4922
if ( (GET_EXC_INDEX(s->freason)) ==
4923
(GET_EXC_INDEX(EXC_FUNCTION_CLAUSE)) ) {
4927
args = make_arglist(c_p, reg, a); /* Overwrite CAR(c_p->ftrace) */
4928
/* Save first stack entry */
4931
s->trace[s->depth++] = c_p->cp;
4934
s->pc = NULL; /* Ignore pc */
4940
/* Package args and stack trace */
4943
hp = HAlloc(c_p, 2);
4944
c_p->ftrace = CONS(hp, args, make_big((Eterm *) s));
4947
/* Save the actual stack trace */
4949
Eterm *ptr, *prev = s->depth ? s->trace[s->depth-1] : NULL;
4950
Uint i_return_trace = beam_return_trace[0];
4951
Uint i_return_to_trace = beam_return_to_trace[0];
4953
* Traverse the stack backwards and add all unique continuation
4954
* pointers to the buffer, up to the maximum stack trace size.
4956
* Skip trace stack frames.
4959
if (ptr < STACK_START(c_p)
4960
&& (is_not_CP(*ptr)|| (*cp_val(*ptr) != i_return_trace &&
4961
*cp_val(*ptr) != i_return_to_trace))
4963
/* Can not follow cp here - code may be unloaded */
4964
Uint *cpp = cp_val((Eterm) c_p->cp);
4965
if (cpp == beam_exception_trace || cpp == beam_return_trace) {
4966
/* Skip return_trace parameters */
4968
} else if (cpp == beam_return_to_trace) {
4969
/* Skip return_to_trace parameters */
4973
while (ptr < STACK_START(c_p) && depth > 0) {
4975
if (*cp_val(*ptr) == i_return_trace) {
4976
/* Skip stack frame variables */
4977
do ++ptr; while (is_not_CP(*ptr));
4978
/* Skip return_trace parameters */
4980
} else if (*cp_val(*ptr) == i_return_to_trace) {
4981
/* Skip stack frame variables */
4982
do ++ptr; while (is_not_CP(*ptr));
3800
/* 2*prev[2] <= 2*c_p->current[2] */
3802
for (i = prev[2]-1; i >= 0; i--) {
3803
a = CONS(hp, reg[i], a);
4984
Eterm *cp = (Eterm *)(*ptr);
4986
/* Record non-duplicates only */
4988
s->trace[s->depth++] = cp;
3807
mfa = TUPLE3(hp, prev[0], prev[1], a);
3810
ASSERT(*next_p == NIL);
3811
*next_p = CONS(hp, mfa, NIL);
3817
* The continuation pointer (c_p->cp) in most cases points to
3818
* a function which we have called and already returned from,
3819
* because the deallocate_return instruction doesn't update c_p->cp.
3820
* Therefore, we will ignore c_p->cp, except for function_clause
3821
* when it *is* accurate.
4999
* Getting the relevant fields from the term pointed to by ftrace
5002
static struct StackTrace *get_trace_from_exc(Eterm exc) {
5006
ASSERT(is_list(exc));
5007
return (struct StackTrace *) big_val(CDR(list_val(exc)));
5011
static Eterm get_args_from_exc(Eterm exc) {
5015
ASSERT(is_list(exc));
5016
return CAR(list_val(exc));
5020
static int is_raised_exc(Eterm exc) {
5024
ASSERT(is_list(exc));
5025
return bignum_header_is_neg(*big_val(CDR(list_val(exc))));
5030
* Creating a list with the argument registers
5033
make_arglist(Process* c_p, Eterm* reg, int a) {
5035
Eterm* hp = HAlloc(c_p, 2*a);
5037
args = CONS(hp, reg[a-1], args);
5045
* Building a symbolic representation of a saved stack trace. Note that
5046
* the exception object 'exc', unless NIL, points to a cons cell which
5047
* holds the given args and the quick-saved data (encoded as a bignum).
5049
* If the bignum is negative, the given args is a complete stacktrace.
5052
build_stacktrace(Process* c_p, Eterm exc) {
5053
struct StackTrace* s;
5058
Eterm* next_p = &Where;
5060
if (! (s = get_trace_from_exc(exc))) {
5063
if (s->freason & EXF_NATIVE) {
5064
/* Just return a null trace if the exception was in native code.
5068
if (is_raised_exc(exc)) {
5069
return get_args_from_exc(exc);
5073
* Find the current function. If the saved s->pc is null, then the
5074
* saved s->current should already contain the proper value.
5076
if (s->pc != NULL) {
5077
current = find_function_from_pc(s->pc);
5079
current = s->current;
5082
* If current is still NULL, default to the initial function
5083
* (e.g. spawn_link(erlang, abs, [1])).
5085
if (current == NULL) {
5086
current = c_p->initial;
5087
args = am_true; /* Just in case */
5089
args = get_args_from_exc(exc);
5095
* Add the {M,F,A} for the current function
5096
* (where A is arity or [Argument]).
5101
Uint heap_size = 6*(depth+1);
5102
Eterm* hp = HAlloc(c_p, heap_size);
5103
Eterm* hp_end = hp + heap_size;
5105
if (args != am_true) {
5106
/* We have an arglist - use it */
5107
mfa = TUPLE3(hp, current[0], current[1], args);
5109
Eterm arity = make_small(current[2]);
5110
mfa = TUPLE3(hp, current[0], current[1], arity);
5113
ASSERT(*next_p == NIL);
5114
*next_p = CONS(hp, mfa, NIL);
5115
next_p = &CDR(list_val(*next_p));
5119
* Finally, we go through the saved continuation pointers.
3824
fi = find_function_from_pc(c_p->cp);
3825
if ( (GET_EXC_INDEX(c_p->freason)) ==
3826
(GET_EXC_INDEX(EXC_FUNCTION_CLAUSE)) &&
3827
fi != NULL && fi != prev && max_depth > 0) {
5121
for (i = 0; i < depth; i++) {
5122
Eterm *fi = find_function_from_pc((Eterm *) s->trace[i]);
5123
if (fi == NULL) continue;
3829
5124
mfa = TUPLE3(hp, fi[0], fi[1], make_small(fi[2]));
3831
5126
ASSERT(*next_p == NIL);
3832
5127
*next_p = CONS(hp, mfa, NIL);
5128
next_p = &CDR(list_val(*next_p));
3839
* Traverse the stack backwards and add all unique functions
3843
if (max_depth != 0) {
3844
/* hp += max_depth*6 */
3845
for (ptr = c_p->stop; ptr < STACK_START(c_p); ptr++) {
3847
fi = find_function_from_pc(cp_val(*ptr));
3848
if (fi != NULL && fi != prev) {
3849
if (max_depth-- <= 1) {
3850
ASSERT(*next_p == NIL);
3855
mfa = TUPLE3(hp, fi[0], fi[1], make_small(fi[2]));
3857
ASSERT(*next_p == NIL);
3858
*next_p = CONS(hp, mfa, NIL);
3867
* Build the final error term: {Value,Where}.
3870
Value = TUPLE2(hp, Value, Where);
3874
if (hp - heap_start > needed) {
3875
erl_exit(1, "%s, line %d: Heap block overrun", __FILE__, __LINE__);
3880
* Save final error term for use by native code.
3882
c_p->fvalue = Value;
3884
if (c_p->current == temp_current) { /* It will go out of scope soon. */
3885
c_p->current = c_p->initial;
3888
if ((c_p->catches <= 0) || (c_p->freason & EXF_PANIC)) {
3890
* No catch active -- terminate the process.
3892
if (c_p->freason & EXF_LOG) {
3894
erl_printf(CBUF, "Error in process ");
3895
display(c_p->id, CBUF);
3896
if (erts_this_node->sysname != am_Noname) {
3897
erl_printf(CBUF, " on node ");
3898
print_atom(atom_val(erts_this_node->sysname), CBUF);
3900
erl_printf(CBUF, " with exit value: ");
3901
ldisplay(Value, CBUF, display_items);
3902
erl_printf(CBUF, "\n");
3903
send_error_to_logger(c_p->group_leader);
3907
* If we use a shared heap, the process will be garbage-collected.
3908
* Must zero c_p->arity to indicate that there are no live registers.
3911
do_exit(c_p, Value);
3916
* Make sure the exception is stable, if anybody looks at
3917
* freason/fvalue again after this point.
3920
c_p->freason = PRIMARY_EXCEPTION(c_p->freason);
3923
* Search for the first catch.
3926
for (ptr = c_p->stop + CP_SIZE; ptr < STACK_START(c_p); ptr++) {
3927
if (is_catch(*ptr)) {
3928
pc = catch_pc(*ptr);
3929
while (is_not_CP(*ptr)) {
3931
ASSERT(c_p->stop <= ptr);
3934
reg[0] = THE_NON_VALUE;
3935
reg[1] = exception_tag[GET_EXC_CLASS(c_p->freason)];
3940
erl_exit(1, "Catch not found");
5131
ASSERT(hp <= hp_end);
5132
HRelease(c_p, hp_end, hp);