void dispatch_exception_pointers(x86_64_emulator& emu,
uint64_t dispatcher,
const EMU_EXCEPTION_POINTERS pointers)
{
constexpr auto mach_frame_size = 0x40;
constexpr auto context_record_size = 0x4F0; // sizeof(CONTEXT64)
const auto exception_record_size = calculate_exception_record_size(...);
const auto combined_size = align_up(
exception_record_size + context_record_size, 0x10);
const auto allocation_size = combined_size + mach_frame_size;
// Allocate on stack
const auto initial_sp = emu.reg(x86_register::rsp);
const auto new_sp = align_down(initial_sp - allocation_size, 0x100);
// Zero memory
vector<uint8_t> zero_memory(initial_sp - new_sp, 0);
emu.write_memory(new_sp, zero_memory.data(), zero_memory.size());
// Write CONTEXT64
emulator_object<CONTEXT64> context_record_obj{emu, new_sp};
context_record_obj.write(*reinterpret_cast<CONTEXT64*>(
pointers.ContextRecord));
// Write EXCEPTION_RECORD
emulator_allocator allocator{emu, new_sp + context_record_size,
exception_record_size};
const auto exception_record_obj = save_exception_record(allocator,
*reinterpret_cast<exception_record*>(pointers.ExceptionRecord));
// Write machine frame (for IRET)
emulator_object<machine_frame> machine_frame_obj{emu,
new_sp + combined_size};
machine_frame_obj.access([&](machine_frame& frame) {
const auto& record = *reinterpret_cast<CONTEXT64*>(
pointers.ContextRecord);
frame.rip = record.Rip;
frame.rsp = record.Rsp;
frame.ss = record.SegSs;
frame.cs = record.SegCs;
frame.eflags = record.EFlags;
});
// Update CPU state
emu.reg(x86_register::rsp, new_sp);
emu.reg(x86_register::rip, dispatcher);
}