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:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user