mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 03:13:55 +00:00
256 lines
7.6 KiB
C++
256 lines
7.6 KiB
C++
#include "event_handler.hpp"
|
|
#include "message_transmitter.hpp"
|
|
#include "windows_emulator.hpp"
|
|
|
|
#include <base64.hpp>
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4244)
|
|
#endif
|
|
|
|
#include "events_generated.hxx"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
namespace debugger
|
|
{
|
|
namespace
|
|
{
|
|
std::optional<Debugger::DebugEventT> receive_event()
|
|
{
|
|
const auto message = receive_message();
|
|
if (message.empty())
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
|
|
const auto data = base64::from_base64(message);
|
|
|
|
flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(data.data()), data.size());
|
|
if (!Debugger::VerifyDebugEventBuffer(verifier))
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
|
|
Debugger::DebugEventT e{};
|
|
Debugger::GetDebugEvent(data.data())->UnPackTo(&e);
|
|
|
|
return {std::move(e)};
|
|
}
|
|
|
|
void send_event(const Debugger::DebugEventT& event)
|
|
{
|
|
flatbuffers::FlatBufferBuilder fbb{};
|
|
fbb.Finish(Debugger::DebugEvent::Pack(fbb, &event));
|
|
|
|
const std::string_view buffer(reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize());
|
|
const auto message = base64::to_base64(buffer);
|
|
|
|
send_message(message);
|
|
}
|
|
|
|
template <typename T>
|
|
requires(!std::is_same_v<std::remove_cvref_t<T>, Debugger::DebugEventT>)
|
|
void send_event(T event)
|
|
{
|
|
Debugger::DebugEventT e{};
|
|
e.event.Set(std::move(event));
|
|
send_event(e);
|
|
}
|
|
|
|
Debugger::State translate_state(const emulation_state state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case emulation_state::paused:
|
|
return Debugger::State_Paused;
|
|
|
|
case emulation_state::none:
|
|
case emulation_state::running:
|
|
return Debugger::State_Running;
|
|
|
|
default:
|
|
return Debugger::State_None;
|
|
}
|
|
}
|
|
|
|
void handle_get_state(const event_context& c)
|
|
{
|
|
Debugger::GetStateResponseT response{};
|
|
response.state = translate_state(c.state);
|
|
|
|
send_event(response);
|
|
}
|
|
|
|
void handle_read_memory(const event_context& c, const Debugger::ReadMemoryRequestT& request)
|
|
{
|
|
std::vector<uint8_t> buffer{};
|
|
buffer.resize(request.size);
|
|
const auto res = c.win_emu.memory.try_read_memory(request.address, buffer.data(), buffer.size());
|
|
|
|
Debugger::ReadMemoryResponseT response{};
|
|
response.address = request.address;
|
|
|
|
if (res)
|
|
{
|
|
response.data = std::move(buffer);
|
|
}
|
|
|
|
send_event(std::move(response));
|
|
}
|
|
|
|
void handle_write_memory(const event_context& c, const Debugger::WriteMemoryRequestT& request)
|
|
{
|
|
bool success{};
|
|
|
|
try
|
|
{
|
|
c.win_emu.memory.write_memory(request.address, request.data.data(), request.data.size());
|
|
success = true;
|
|
}
|
|
catch (...)
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
Debugger::WriteMemoryResponseT response{};
|
|
response.address = request.address;
|
|
response.size = static_cast<uint32_t>(request.data.size());
|
|
response.success = success;
|
|
|
|
send_event(response);
|
|
}
|
|
|
|
void handle_read_register(const event_context& c, const Debugger::ReadRegisterRequestT& request)
|
|
{
|
|
std::array<uint8_t, 512> buffer{};
|
|
const auto res = c.win_emu.emu().read_register(static_cast<x86_register>(request.register_), buffer.data(), buffer.size());
|
|
|
|
const auto size = std::min(buffer.size(), res);
|
|
|
|
Debugger::ReadRegisterResponseT response{};
|
|
response.register_ = request.register_;
|
|
response.data.assign(buffer.data(), buffer.data() + size);
|
|
|
|
send_event(std::move(response));
|
|
}
|
|
|
|
void handle_write_register(const event_context& c, const Debugger::WriteRegisterRequestT& request)
|
|
{
|
|
bool success{};
|
|
size_t size = request.data.size();
|
|
|
|
try
|
|
{
|
|
size =
|
|
c.win_emu.emu().write_register(static_cast<x86_register>(request.register_), request.data.data(), request.data.size());
|
|
success = true;
|
|
}
|
|
catch (...)
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
Debugger::WriteRegisterResponseT response{};
|
|
response.register_ = request.register_;
|
|
response.size = static_cast<uint32_t>(size);
|
|
response.success = success;
|
|
|
|
send_event(response);
|
|
}
|
|
|
|
void handle_event(event_context& c, const Debugger::DebugEventT& e)
|
|
{
|
|
switch (e.event.type)
|
|
{
|
|
case Debugger::Event_PauseRequest:
|
|
c.state = emulation_state::paused;
|
|
break;
|
|
|
|
case Debugger::Event_RunRequest:
|
|
c.state = emulation_state::running;
|
|
break;
|
|
|
|
case Debugger::Event_GetStateRequest:
|
|
handle_get_state(c);
|
|
break;
|
|
|
|
case Debugger::Event_ReadMemoryRequest:
|
|
handle_read_memory(c, *e.event.AsReadMemoryRequest());
|
|
break;
|
|
|
|
case Debugger::Event_WriteMemoryRequest:
|
|
handle_write_memory(c, *e.event.AsWriteMemoryRequest());
|
|
break;
|
|
|
|
case Debugger::Event_ReadRegisterRequest:
|
|
handle_read_register(c, *e.event.AsReadRegisterRequest());
|
|
break;
|
|
|
|
case Debugger::Event_WriteRegisterRequest:
|
|
handle_write_register(c, *e.event.AsWriteRegisterRequest());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void handle_events_once(event_context& c)
|
|
{
|
|
while (true)
|
|
{
|
|
suspend_execution(0ms);
|
|
|
|
const auto e = receive_event();
|
|
if (!e.has_value())
|
|
{
|
|
break;
|
|
}
|
|
|
|
handle_event(c, *e);
|
|
}
|
|
}
|
|
|
|
void handle_events(event_context& c)
|
|
{
|
|
update_emulation_status(c.win_emu);
|
|
|
|
while (true)
|
|
{
|
|
handle_events_once(c);
|
|
|
|
if (c.state != emulation_state::paused)
|
|
{
|
|
break;
|
|
}
|
|
|
|
suspend_execution(2ms);
|
|
}
|
|
}
|
|
|
|
void update_emulation_status(const windows_emulator& win_emu)
|
|
{
|
|
const auto memory_status = win_emu.memory.compute_memory_stats();
|
|
|
|
Debugger::EmulationStatusT status{};
|
|
status.reserved_memory = memory_status.reserved_memory;
|
|
status.committed_memory = memory_status.committed_memory;
|
|
status.executed_instructions = win_emu.get_executed_instructions();
|
|
status.active_threads = static_cast<uint32_t>(win_emu.process.threads.size());
|
|
send_event(status);
|
|
}
|
|
|
|
void handle_exit(const windows_emulator& win_emu, std::optional<NTSTATUS> exit_status)
|
|
{
|
|
update_emulation_status(win_emu);
|
|
|
|
Debugger::ApplicationExitT response{};
|
|
response.exit_status = exit_status;
|
|
send_event(response);
|
|
}
|
|
} |