#pragma once #include #include #include #include #define REGISTER1( NAME ) \ private: \ alignas(4) std::array NAME##_storage = {{0,0,0,0}}; \ public: \ uint32_t& e##NAME##x() { \ return *reinterpret_cast(NAME##_storage.data()); \ } \ \ uint16_t& NAME##x() { \ return *reinterpret_cast(NAME##_storage.data()); \ } \ \ uint8_t& NAME##h() { \ return *reinterpret_cast(NAME##_storage.data()+1); \ } \ \ uint8_t& NAME##l() { \ return *reinterpret_cast(NAME##_storage.data()); \ } \ #define REGISTER2( NAME ) \ private: \ alignas(4) std::array NAME##_storage = {{0,0,0,0}}; \ public: \ uint32_t& e##NAME() { \ return *reinterpret_cast(NAME##_storage.data()); \ } \ \ uint16_t& NAME() { \ return *reinterpret_cast(NAME##_storage.data()); \ } \ #define EFLAGS \ private: \ alignas(8) std::bitset<32> storage = 2; \ public: \ using ref = std::bitset<32>::reference; \ ref cf() { return storage[0]; } \ ref pf() { return storage[2]; } \ ref af() { return storage[4]; } \ ref zf() { return storage[6]; } \ ref sf() { return storage[7]; } \ ref tf() { return storage[8]; } \ ref intf() { return storage[9]; } \ ref df() { return storage[10]; } \ ref of() { return storage[11]; } \ /*TODO: iopl*/ \ ref nt() { return storage[14]; } \ ref rf() { return storage[16]; } \ ref vm() { return storage[17]; } \ ref ac() { return storage[18]; } \ ref vif() { return storage[19]; } \ ref vip() { return storage[20]; } \ ref id() { return storage[21]; } \ struct CpuState { REGISTER2(ip) REGISTER1(a) REGISTER1(c) REGISTER1(d) REGISTER1(b) REGISTER2(sp) REGISTER2(bp) REGISTER2(si) REGISTER2(di) EFLAGS }; #undef REGISTER1 #undef REGISTER2 #undef EFLAGS std::ostream& operator<<(std::ostream& os, CpuState& cpu) { os << "EIP: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.eip() << std::endl << "EAX: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.eax() << std::endl << "EBX: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.ebx() << std::endl << "ECX: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.ecx() << std::endl << "EDX: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.edx() << std::endl << "ESP: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.esp() << std::endl << "EBP: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.ebp() << std::endl << "ESI: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.esi() << std::endl << "EDI: 0x" << std::hex << std::setw(8) << std::setfill('0') << cpu.edi() << std::endl << "cf \tpf \taf \tzf \tsf \ttf \tintf \tdf \tof \tnt \trf \tvm \tac \tvif \tvip \tid" << std::endl << cpu.cf() << "\t" << cpu.pf() << "\t" << cpu.af() << "\t" << cpu.zf() << "\t" << cpu.sf() << "\t" << cpu.tf() << "\t" << cpu.intf() << "\t" << cpu.df() << "\t" << cpu.of() << "\t" << cpu.nt() << "\t" << cpu.rf() << "\t" << cpu.vm() << "\t" << cpu.ac() << "\t" << cpu.vif() << "\t" << cpu.vip() << "\t" << cpu.id() << "\t" << std::endl; return os; }