summaryrefslogtreecommitdiffstats
path: root/asmrun/backtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'asmrun/backtrace.c')
-rw-r--r--asmrun/backtrace.c115
1 files changed, 77 insertions, 38 deletions
diff --git a/asmrun/backtrace.c b/asmrun/backtrace.c
index 3854967cf..5eb8600cd 100644
--- a/asmrun/backtrace.c
+++ b/asmrun/backtrace.c
@@ -30,6 +30,17 @@ code_t * caml_backtrace_buffer = NULL;
value caml_backtrace_last_exn = Val_unit;
#define BACKTRACE_BUFFER_SIZE 1024
+/* In order to prevent the GC from walking through the debug information
+ (which have no headers), we transform frame_descr pointers into
+ 31/63 bits ocaml integers by shifting them by 1 to the right. We do
+ not lose information as descr pointers are aligned.
+
+ In particular, we do not need to use [caml_initialize] when setting
+ an array element with such a value.
+*/
+#define Val_Descrptr(descr) Val_long((uintnat)descr>>1)
+#define Descrptr_Val(v) ((frame_descr *) (Long_val(v)<<1))
+
/* Start or stop the backtrace machinery */
CAMLprim value caml_record_backtrace(value vflag)
@@ -112,6 +123,7 @@ void caml_stash_backtrace(value exn, uintnat pc, char * sp, char * trapsp)
caml_backtrace_last_exn = exn;
}
if (caml_backtrace_buffer == NULL) {
+ Assert(caml_backtrace_pos == 0);
caml_backtrace_buffer = malloc(BACKTRACE_BUFFER_SIZE * sizeof(code_t));
if (caml_backtrace_buffer == NULL) return;
}
@@ -172,7 +184,7 @@ CAMLprim value caml_get_current_callstack(value max_frames_value) {
}
}
- trace = caml_alloc((mlsize_t) trace_size, Abstract_tag);
+ trace = caml_alloc((mlsize_t) trace_size, 0);
/* then collect the trace */
{
@@ -183,11 +195,7 @@ CAMLprim value caml_get_current_callstack(value max_frames_value) {
for (trace_pos = 0; trace_pos < trace_size; trace_pos++) {
frame_descr * descr = caml_next_frame_descriptor(&pc, &sp);
Assert(descr != NULL);
- /* The assignment below is safe without [caml_initialize], even
- if the trace is large and allocated on the old heap, because
- we assign values that are outside the OCaml heap. */
- Assert(!(Is_block((value) descr) && Is_in_heap((value) descr)));
- Field(trace, trace_pos) = (value) descr;
+ Field(trace, trace_pos) = Val_Descrptr(descr);
}
}
@@ -209,7 +217,7 @@ static void extract_location_info(frame_descr * d,
/*out*/ struct loc_info * li)
{
uintnat infoptr;
- uint32 info1, info2;
+ uint32_t info1, info2;
/* If no debugging information available, print nothing.
When everything is compiled with -g, this corresponds to
@@ -224,8 +232,8 @@ static void extract_location_info(frame_descr * d,
sizeof(char *) + sizeof(short) + sizeof(short) +
sizeof(short) * d->num_live + sizeof(frame_descr *) - 1)
& -sizeof(frame_descr *);
- info1 = ((uint32 *)infoptr)[0];
- info2 = ((uint32 *)infoptr)[1];
+ info1 = ((uint32_t *)infoptr)[0];
+ info2 = ((uint32_t *)infoptr)[1];
/* Format of the two info words:
llllllllllllllllllll aaaaaaaa bbbbbbbbbb nnnnnnnnnnnnnnnnnnnnnnnn kk
44 36 26 2 0
@@ -295,31 +303,27 @@ void caml_print_exception_backtrace(void)
/* Convert the raw backtrace to a data structure usable from OCaml */
-CAMLprim value caml_convert_raw_backtrace(value backtrace) {
- CAMLparam1(backtrace);
- CAMLlocal4(res, arr, p, fname);
- int i;
+CAMLprim value caml_convert_raw_backtrace_slot(value backtrace_slot) {
+ CAMLparam1(backtrace_slot);
+ CAMLlocal2(p, fname);
struct loc_info li;
- arr = caml_alloc(Wosize_val(backtrace), 0);
- for (i = 0; i < Wosize_val(backtrace); i++) {
- extract_location_info((frame_descr *) Field(backtrace, i), &li);
- if (li.loc_valid) {
- fname = caml_copy_string(li.loc_filename);
- p = caml_alloc_small(5, 0);
- Field(p, 0) = Val_bool(li.loc_is_raise);
- Field(p, 1) = fname;
- Field(p, 2) = Val_int(li.loc_lnum);
- Field(p, 3) = Val_int(li.loc_startchr);
- Field(p, 4) = Val_int(li.loc_endchr);
- } else {
- p = caml_alloc_small(1, 1);
- Field(p, 0) = Val_bool(li.loc_is_raise);
- }
- caml_modify(&Field(arr, i), p);
+ extract_location_info(Descrptr_Val(backtrace_slot), &li);
+
+ if (li.loc_valid) {
+ fname = caml_copy_string(li.loc_filename);
+ p = caml_alloc_small(5, 0);
+ Field(p, 0) = Val_bool(li.loc_is_raise);
+ Field(p, 1) = fname;
+ Field(p, 2) = Val_int(li.loc_lnum);
+ Field(p, 3) = Val_int(li.loc_startchr);
+ Field(p, 4) = Val_int(li.loc_endchr);
+ } else {
+ p = caml_alloc_small(1, 1);
+ Field(p, 0) = Val_bool(li.loc_is_raise);
}
- res = caml_alloc_small(1, 0); Field(res, 0) = arr; /* Some */
- CAMLreturn(res);
+
+ CAMLreturn(p);
}
/* Get a copy of the latest backtrace */
@@ -328,10 +332,37 @@ CAMLprim value caml_get_exception_raw_backtrace(value unit)
{
CAMLparam0();
CAMLlocal1(res);
- res = caml_alloc(caml_backtrace_pos, Abstract_tag);
- if(caml_backtrace_buffer != NULL)
- memcpy(&Field(res, 0), caml_backtrace_buffer,
- caml_backtrace_pos * sizeof(code_t));
+ const int tag = 0;
+
+ /* Beware: the allocations below may cause finalizers to be run, and another
+ backtrace---possibly of a different length---to be stashed (for example
+ if the finalizer raises then catches an exception). We choose to ignore
+ any such finalizer backtraces and return the original one. */
+
+ if (caml_backtrace_buffer == NULL || caml_backtrace_pos == 0) {
+ res = caml_alloc(0, tag);
+ }
+ else {
+ code_t saved_caml_backtrace_buffer[BACKTRACE_BUFFER_SIZE];
+ int saved_caml_backtrace_pos;
+ intnat i;
+
+ saved_caml_backtrace_pos = caml_backtrace_pos;
+
+ if (saved_caml_backtrace_pos > BACKTRACE_BUFFER_SIZE) {
+ saved_caml_backtrace_pos = BACKTRACE_BUFFER_SIZE;
+ }
+
+ memcpy(saved_caml_backtrace_buffer, caml_backtrace_buffer,
+ saved_caml_backtrace_pos * sizeof(code_t));
+
+ res = caml_alloc(saved_caml_backtrace_pos, tag);
+ for (i = 0; i < saved_caml_backtrace_pos; i++) {
+ /* [Val_Descrptr] always returns an immediate. */
+ Field(res, i) = Val_Descrptr(saved_caml_backtrace_buffer[i]);
+ }
+ }
+
CAMLreturn(res);
}
@@ -348,8 +379,16 @@ CAMLprim value caml_get_exception_raw_backtrace(value unit)
CAMLprim value caml_get_exception_backtrace(value unit)
{
CAMLparam0();
- CAMLlocal2(raw,res);
- raw = caml_get_exception_raw_backtrace(unit);
- res = caml_convert_raw_backtrace(raw);
+ CAMLlocal3(arr, res, backtrace);
+ intnat i;
+
+ backtrace = caml_get_exception_raw_backtrace(Val_unit);
+
+ arr = caml_alloc(Wosize_val(backtrace), 0);
+ for (i = 0; i < Wosize_val(backtrace); i++) {
+ Store_field(arr, i, caml_convert_raw_backtrace_slot(Field(backtrace, i)));
+ }
+
+ res = caml_alloc_small(1, 0); Field(res, 0) = arr; /* Some */
CAMLreturn(res);
}