Signal handling in native code without the page table (#9682)
Signal handlers sometimes need to know whether the signal occurred in ocamlopt-generated code, as opposed to runtime or C library code. Today this determination uses a page table lookup to keep track of dynamically-loaded modules, plus ad-hoc tests for the main program. This PR uses the code fragment table instead. That's more reliable, less ad-hoc, and independent of the page table. i386nt.asm: add caml_system__code_{begin,end}, ,like in the other ports.master
parent
603506aa34
commit
e4bf109d1e
|
@ -26,9 +26,14 @@
|
|||
EXTERN _caml_stash_backtrace: PROC
|
||||
EXTERN _Caml_state: DWORD
|
||||
|
||||
.CODE
|
||||
|
||||
PUBLIC _caml_system__code_begin
|
||||
_caml_system__code_begin:
|
||||
ret ; just one instruction, so that debuggers don't display
|
||||
; caml_system__code_begin instead of caml_call_gc
|
||||
; Allocation
|
||||
|
||||
.CODE
|
||||
PUBLIC _caml_call_gc
|
||||
PUBLIC _caml_alloc1
|
||||
PUBLIC _caml_alloc2
|
||||
|
@ -292,6 +297,9 @@ _caml_ml_array_bound_error:
|
|||
mov eax, offset _caml_array_bound_error
|
||||
jmp _caml_c_call
|
||||
|
||||
PUBLIC _caml_system__code_end
|
||||
_caml_system__code_end:
|
||||
|
||||
.DATA
|
||||
PUBLIC _caml_system__frametable
|
||||
_caml_system__frametable LABEL DWORD
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "caml/codefrag.h"
|
||||
#include "caml/fail.h"
|
||||
#include "caml/memory.h"
|
||||
#include "caml/osdeps.h"
|
||||
|
@ -49,18 +50,6 @@ extern signal_handler caml_win32_signal(int sig, signal_handler action);
|
|||
extern void caml_win32_overflow_detection();
|
||||
#endif
|
||||
|
||||
extern char * caml_code_area_start, * caml_code_area_end;
|
||||
extern char caml_system__code_begin, caml_system__code_end;
|
||||
|
||||
/* Do not use the macro from address_class.h here. */
|
||||
#undef Is_in_code_area
|
||||
#define Is_in_code_area(pc) \
|
||||
( ((char *)(pc) >= caml_code_area_start && \
|
||||
(char *)(pc) <= caml_code_area_end) \
|
||||
|| ((char *)(pc) >= &caml_system__code_begin && \
|
||||
(char *)(pc) <= &caml_system__code_end) \
|
||||
|| (Classify_addr(pc) & In_code_area) )
|
||||
|
||||
/* This routine is the common entry point for garbage collection
|
||||
and signal handling. It can trigger a callback to OCaml code.
|
||||
With system threads, this callback can cause a context switch.
|
||||
|
@ -119,7 +108,7 @@ DECLARE_SIGNAL_HANDLER(handle_signal)
|
|||
Use the signal context to modify that register too, but only if
|
||||
we are inside OCaml code (not inside C code). */
|
||||
#if defined(CONTEXT_PC) && defined(CONTEXT_YOUNG_LIMIT)
|
||||
if (Is_in_code_area(CONTEXT_PC))
|
||||
if (caml_find_code_fragment_by_pc((char *) CONTEXT_PC) != NULL)
|
||||
CONTEXT_YOUNG_LIMIT = (context_reg) Caml_state->young_limit;
|
||||
#endif
|
||||
}
|
||||
|
@ -226,7 +215,7 @@ DECLARE_SIGNAL_HANDLER(segv_handler)
|
|||
&& fault_addr < Caml_state->top_of_stack
|
||||
&& (uintnat)fault_addr >= CONTEXT_SP - EXTRA_STACK
|
||||
#ifdef CONTEXT_PC
|
||||
&& Is_in_code_area(CONTEXT_PC)
|
||||
&& caml_find_code_fragment_by_pc((char *) CONTEXT_PC) != NULL
|
||||
#endif
|
||||
) {
|
||||
#ifdef RETURN_AFTER_STACK_OVERFLOW
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
extern int caml_parser_trace;
|
||||
char * caml_code_area_start, * caml_code_area_end;
|
||||
extern char caml_system__code_begin, caml_system__code_end;
|
||||
|
||||
/* Initialize the atom table and the static data and code area limits. */
|
||||
|
||||
|
@ -81,6 +82,10 @@ static void init_static(void)
|
|||
caml_register_code_fragment(caml_code_area_start,
|
||||
caml_code_area_end,
|
||||
DIGEST_LATER, NULL);
|
||||
/* Also register the glue code written in assembly */
|
||||
caml_register_code_fragment(&caml_system__code_begin,
|
||||
&caml_system__code_end,
|
||||
DIGEST_IGNORE, NULL);
|
||||
}
|
||||
|
||||
/* These are termination hooks used by the systhreads library */
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include "caml/alloc.h"
|
||||
#include "caml/address_class.h"
|
||||
#include "caml/codefrag.h"
|
||||
#include "caml/fail.h"
|
||||
#include "caml/io.h"
|
||||
#include "caml/memory.h"
|
||||
|
@ -539,7 +539,8 @@ static LONG CALLBACK
|
|||
DWORD *ctx_ip = &(ctx->Eip);
|
||||
DWORD *ctx_sp = &(ctx->Esp);
|
||||
|
||||
if (code == EXCEPTION_STACK_OVERFLOW && Is_in_code_area (*ctx_ip))
|
||||
if (code == EXCEPTION_STACK_OVERFLOW &&
|
||||
caml_find_code_fragment_by_pc((char *) (*ctx_ip)) != NULL)
|
||||
{
|
||||
uintnat faulting_address;
|
||||
uintnat * alt_esp;
|
||||
|
@ -561,24 +562,14 @@ static LONG CALLBACK
|
|||
|
||||
#else
|
||||
|
||||
/* Do not use the macro from address_class.h here. */
|
||||
#undef Is_in_code_area
|
||||
#define Is_in_code_area(pc) \
|
||||
( ((char *)(pc) >= caml_code_area_start && \
|
||||
(char *)(pc) <= caml_code_area_end) \
|
||||
|| ((char *)(pc) >= &caml_system__code_begin && \
|
||||
(char *)(pc) <= &caml_system__code_end) \
|
||||
|| (Classify_addr(pc) & In_code_area) )
|
||||
extern char caml_system__code_begin, caml_system__code_end;
|
||||
|
||||
|
||||
static LONG CALLBACK
|
||||
caml_stack_overflow_VEH (EXCEPTION_POINTERS* exn_info)
|
||||
{
|
||||
DWORD code = exn_info->ExceptionRecord->ExceptionCode;
|
||||
CONTEXT *ctx = exn_info->ContextRecord;
|
||||
|
||||
if (code == EXCEPTION_STACK_OVERFLOW && Is_in_code_area (ctx->Rip))
|
||||
if (code == EXCEPTION_STACK_OVERFLOW &&
|
||||
caml_find_code_fragment_by_pc((char *) (ctx->Rip)) != NULL)
|
||||
{
|
||||
uintnat faulting_address;
|
||||
uintnat * alt_rsp;
|
||||
|
|
Loading…
Reference in New Issue