diff --git a/src/windows-emulator/debugging/x64_gdb_stub_handler.hpp b/src/windows-emulator/debugging/x64_gdb_stub_handler.hpp index 4489a03f..c1cf111c 100644 --- a/src/windows-emulator/debugging/x64_gdb_stub_handler.hpp +++ b/src/windows-emulator/debugging/x64_gdb_stub_handler.hpp @@ -5,17 +5,102 @@ #include #include "x64_target_descriptions.hpp" +#include -inline std::vector gdb_registers{ - x64_register::rax, x64_register::rbx, x64_register::rcx, x64_register::rdx, x64_register::rsi, x64_register::rdi, - x64_register::rbp, x64_register::rsp, x64_register::r8, x64_register::r9, x64_register::r10, x64_register::r11, - x64_register::r12, x64_register::r13, x64_register::r14, x64_register::r15, x64_register::rip, x64_register::rflags, - /*x64_register::cs, - x64_register::ss, - x64_register::ds, - x64_register::es, - x64_register::fs, - x64_register::gs,*/ +struct register_entry +{ + x64_register reg; + std::optional expected_size; + std::optional offset; + + register_entry(const x64_register reg = x64_register::invalid, + const std::optional expected_size = std::nullopt, + const std::optional offset = std::nullopt) + : reg(reg), + expected_size(expected_size), + offset(offset) + { + } +}; + +inline std::vector gdb_registers{ + x64_register::rax, + x64_register::rbx, + x64_register::rcx, + x64_register::rdx, + x64_register::rsi, + x64_register::rdi, + x64_register::rbp, + x64_register::rsp, + x64_register::r8, + x64_register::r9, + x64_register::r10, + x64_register::r11, + x64_register::r12, + x64_register::r13, + x64_register::r14, + x64_register::r15, + x64_register::rip, + x64_register::eflags, + {x64_register::cs, 4}, + {x64_register::ss, 4}, + {x64_register::ds, 4}, + {x64_register::es, 4}, + {x64_register::fs, 4}, + {x64_register::gs, 4}, + x64_register::st0, + x64_register::st1, + x64_register::st2, + x64_register::st3, + x64_register::st4, + x64_register::st5, + x64_register::st6, + x64_register::st7, + + {x64_register::fpcw, 4}, // fctrl + {x64_register::fpsw, 4}, // fstat + {x64_register::fptag, 4}, // ftag + {x64_register::fcs, 4}, // fiseg + {x64_register::fip, 4}, // fioff + {x64_register::fds, 4}, // foseg + {x64_register::fdp, 4}, // fooff + {x64_register::fop, 4}, // fop + + x64_register::xmm0, + x64_register::xmm1, + x64_register::xmm2, + x64_register::xmm3, + x64_register::xmm4, + x64_register::xmm5, + x64_register::xmm6, + x64_register::xmm7, + x64_register::xmm8, + x64_register::xmm9, + x64_register::xmm10, + x64_register::xmm11, + x64_register::xmm12, + x64_register::xmm13, + x64_register::xmm14, + x64_register::xmm15, + x64_register::mxcsr, + x64_register::fs_base, + x64_register::gs_base, + {x64_register::ymm0, std::nullopt, 16}, + {x64_register::ymm1, std::nullopt, 16}, + {x64_register::ymm2, std::nullopt, 16}, + {x64_register::ymm3, std::nullopt, 16}, + {x64_register::ymm4, std::nullopt, 16}, + {x64_register::ymm5, std::nullopt, 16}, + {x64_register::ymm6, std::nullopt, 16}, + {x64_register::ymm7, std::nullopt, 16}, + {x64_register::ymm8, std::nullopt, 16}, + {x64_register::ymm9, std::nullopt, 16}, + {x64_register::ymm10, std::nullopt, 16}, + {x64_register::ymm11, std::nullopt, 16}, + {x64_register::ymm12, std::nullopt, 16}, + {x64_register::ymm13, std::nullopt, 16}, + {x64_register::ymm14, std::nullopt, 16}, + {x64_register::ymm15, std::nullopt, 16}, }; inline memory_operation map_breakpoint_type(const gdb_stub::breakpoint_type type) @@ -117,7 +202,24 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler return 0; } - return this->emu_->read_register(gdb_registers[reg], data, max_length); + const auto real_reg = gdb_registers[reg]; + + auto size = this->emu_->read_register(real_reg.reg, data, max_length); + + if (real_reg.offset) + { + size -= *real_reg.offset; + memcpy(data, static_cast(data) + *real_reg.offset, size); + } + + const auto result_size = real_reg.expected_size.value_or(size); + + if (result_size > size) + { + memset(static_cast(data) + size, 0, result_size - size); + } + + return result_size; } catch (...) { @@ -134,7 +236,31 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler return 0; } - return this->emu_->write_register(gdb_registers[reg], data, size); + const auto real_reg = gdb_registers[reg]; + + size_t written_size = 0; + + if (real_reg.offset) + { + std::vector full_data{}; + full_data.resize(this->get_max_register_size()); + + written_size = this->emu_->read_register(real_reg.reg, full_data.data(), full_data.size()); + if (written_size < *real_reg.offset) + { + return 0; + } + + memcpy(full_data.data() + *real_reg.offset, data, written_size - *real_reg.offset); + this->emu_->write_register(real_reg.reg, full_data.data(), written_size); + written_size -= *real_reg.offset; + } + else + { + written_size = this->emu_->write_register(real_reg.reg, data, size); + } + + return real_reg.expected_size.value_or(written_size); } catch (...) {