Expose more info in signal handler mcontext

Add the following:

- CS and SS registers
- For 32bit: DS, ES, FS, GS registers (on 64 bit these are not part of
  the iframe structure)
- CR2 register (fault address)
- Hardware interrupt number
- Hardware error code

The hardware error code, interrupt number and fault address are not
modifiable by the signal handlers. The other registers can be modified.

This is used for example in dosemu to intercept errors from JIT generated
code and resume execution. Wine can also make use of it.

In order to not change the size of struct mcontext, these are inserted
in a region of the FXSAVE structure that is available for the OS to
store some data (as documented by Intel) and that we didn't use before.

Fixes #7867

Change-Id: Ia3c27a2c728e32995196c646c1d78adf40e793ed
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9456
Reviewed-by: Adrien Destugues <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
PulkoMandy
2025-07-19 18:00:39 +00:00
committed by waddlesplash
parent a80ef5700c
commit 11adda21aa
4 changed files with 69 additions and 4 deletions
+21 -1
View File
@@ -34,6 +34,8 @@ typedef struct packed_mmx_regs {
unsigned char mm7[10];
} packed_mmx_regs;
// The layout of this structure matches the one used by the FSAVE/FNSAVE instruction, so the
// context can be loaded directly in the FPU if that instruction is available.
typedef struct old_extended_regs {
unsigned short fp_control;
unsigned short _reserved1;
@@ -102,6 +104,8 @@ typedef struct xmmx_regs {
unsigned char xmm7[16];
} xmmx_regs;
// The layout matches the one used by the FXSAVE instruction, so that the context can be loaded
// quickly into the FPU using that.
typedef struct new_extended_regs {
unsigned short fp_control;
unsigned short fp_status;
@@ -120,7 +124,23 @@ typedef struct new_extended_regs {
mmx_regs mmx;
} fp_mmx;
xmmx_regs xmmx;
unsigned char _reserved_288_511[224];
unsigned char _reserved_288_463[176];
// This area is explicitly not read and written by the XSAVE and FXSAVE instructions
// according to Intel documentation. Which is good news, because we have a few more things
// of our own to store...
unsigned long fault_address;
unsigned long error_code;
unsigned short cs;
unsigned short ds;
unsigned short es;
unsigned short fs;
unsigned short gs;
unsigned short ss;
unsigned char trap_number;
unsigned char _available_485_511[27];
} new_extended_regs;
typedef struct extended_regs {
+14 -3
View File
@@ -16,7 +16,6 @@ struct x86_64_fp_register {
unsigned char reserved[6];
};
struct x86_64_xmm_register {
unsigned char value[16];
};
@@ -39,7 +38,19 @@ struct fpu_state {
};
struct x86_64_xmm_register xmm[16];
unsigned char _reserved_416_511[96];
unsigned char _reserved_416_463[48];
// This area is explicitly not read and written by the XSAVE and FXSAVE instructions
// according to Intel documentation. Which is good news, because we have a few more things
// of our own to store...
unsigned long fault_address;
unsigned long error_code;
unsigned short cs;
unsigned short ss;
unsigned char trap_number;
unsigned char _available_485_511[27];
};
@@ -50,7 +61,7 @@ struct xstate_hdr {
};
// The layout of this struct matches the one used by the FXSAVE instruction on
// The layout of this struct matches the one used by the XSAVE instruction on
// an AVX CPU
struct savefpu {
struct fpu_state fp_fxsave;
+21
View File
@@ -322,6 +322,16 @@ arch_setup_signal_frame(Thread* thread, struct sigaction* action,
// Fill in signalFrameData->context.uc_stack
signal_get_user_stack(frame->user_sp, &signalFrameData->context.uc_stack);
signalFrameData->context.uc_mcontext.xregs.state.new_format.fault_address = x86_read_cr2();
signalFrameData->context.uc_mcontext.xregs.state.new_format.error_code = frame->error_code;
signalFrameData->context.uc_mcontext.xregs.state.new_format.cs = frame->cs;
signalFrameData->context.uc_mcontext.xregs.state.new_format.ds = frame->ds;
signalFrameData->context.uc_mcontext.xregs.state.new_format.es = frame->es;
signalFrameData->context.uc_mcontext.xregs.state.new_format.fs = frame->fs;
signalFrameData->context.uc_mcontext.xregs.state.new_format.gs = frame->gs;
signalFrameData->context.uc_mcontext.xregs.state.new_format.ss = frame->user_ss;
signalFrameData->context.uc_mcontext.xregs.state.new_format.trap_number = frame->vector;
// store orig_eax/orig_edx in syscall_restart_return_value
signalFrameData->syscall_restart_return_value
= (uint64)frame->orig_edx << 32 | frame->orig_eax;
@@ -388,6 +398,17 @@ arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
frame->si = signalFrameData->context.uc_mcontext.esi;
frame->bx = signalFrameData->context.uc_mcontext.ebx;
// Note: the error_code and vector fields are not restored. These are provided to the signal
// handler for information purposes only, and are not used after the signal handling is
// complete.
frame->cs = signalFrameData->context.uc_mcontext.xregs.state.new_format.cs;
frame->ds = signalFrameData->context.uc_mcontext.xregs.state.new_format.ds;
frame->es = signalFrameData->context.uc_mcontext.xregs.state.new_format.es;
frame->fs = signalFrameData->context.uc_mcontext.xregs.state.new_format.fs;
frame->gs = signalFrameData->context.uc_mcontext.xregs.state.new_format.gs;
frame->user_ss = signalFrameData->context.uc_mcontext.xregs.state.new_format.ss;
x86_frstor((void*)(&signalFrameData->context.uc_mcontext.xregs));
TRACE(("### arch_restore_signal_frame: exit\n"));
+13
View File
@@ -378,6 +378,12 @@ arch_setup_signal_frame(Thread* thread, struct sigaction* action,
sInitialState.user_fpu_state, gFPUSaveLength);
}
signalFrameData->context.uc_mcontext.fpu.fp_fxsave.fault_address = x86_read_cr2();
signalFrameData->context.uc_mcontext.fpu.fp_fxsave.error_code = frame->error_code;
signalFrameData->context.uc_mcontext.fpu.fp_fxsave.cs = frame->cs;
signalFrameData->context.uc_mcontext.fpu.fp_fxsave.ss = frame->ss;
signalFrameData->context.uc_mcontext.fpu.fp_fxsave.trap_number = frame->vector;
// Fill in signalFrameData->context.uc_stack.
signal_get_user_stack(frame->user_sp, &signalFrameData->context.uc_stack);
@@ -445,6 +451,13 @@ arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
frame->flags = (frame->flags & ~(uint64)X86_EFLAGS_USER_FLAGS)
| (signalFrameData->context.uc_mcontext.rflags & X86_EFLAGS_USER_FLAGS);
// Note: the error_code and vector fields are not restored. These are provided to the signal
// handler for information purposes only, and are not used after the signal handling is
// complete.
frame->cs = signalFrameData->context.uc_mcontext.fpu.fp_fxsave.cs;
frame->ss = signalFrameData->context.uc_mcontext.fpu.fp_fxsave.ss;
Thread* thread = thread_get_current_thread();
memcpy(thread->arch_info.user_fpu_state,