mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-28 07:21:02 +00:00
Cleanup snapshot generation
This commit is contained in:
@@ -4,9 +4,8 @@
|
||||
#include <win_x64_gdb_stub_handler.hpp>
|
||||
|
||||
#include "object_watching.hpp"
|
||||
#include "snapshot.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/compression.hpp>
|
||||
#include <utils/interupt_handler.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
@@ -26,67 +25,6 @@ namespace
|
||||
std::unordered_map<windows_path, std::filesystem::path> path_mappings{};
|
||||
};
|
||||
|
||||
std::vector<uint8_t> build_dump_data(const windows_emulator& win_emu)
|
||||
{
|
||||
utils::buffer_serializer serializer{};
|
||||
win_emu.serialize(serializer);
|
||||
|
||||
auto compressed_data = utils::compression::zlib::compress(serializer.get_buffer());
|
||||
|
||||
// TODO: Add version
|
||||
compressed_data.insert(compressed_data.begin(), {'E', 'D', 'M', 'P'});
|
||||
|
||||
return compressed_data;
|
||||
}
|
||||
|
||||
std::string get_main_executable_name(const windows_emulator& win_emu)
|
||||
{
|
||||
const auto* exe = win_emu.mod_manager.executable;
|
||||
if (exe)
|
||||
{
|
||||
return std::filesystem::path(exe->name).stem().string();
|
||||
}
|
||||
|
||||
return "process";
|
||||
}
|
||||
|
||||
void generate_dump(const windows_emulator& win_emu)
|
||||
{
|
||||
std::filesystem::path dump = get_main_executable_name(win_emu) + "-" + std::to_string(time(nullptr)) + ".edmp";
|
||||
win_emu.log.log("Writing to %s...\n", dump.string().c_str());
|
||||
|
||||
const auto data = build_dump_data(win_emu);
|
||||
utils::io::write_file(dump, data);
|
||||
}
|
||||
|
||||
void load_dump_data(windows_emulator& win_emu, const std::span<const uint8_t> data)
|
||||
{
|
||||
if (data.size() < 4 || memcmp(data.data(), "EDMP", 4) != 0)
|
||||
{
|
||||
throw std::runtime_error("Invalid dump");
|
||||
}
|
||||
|
||||
const auto plain_data = utils::compression::zlib::decompress(data.subspan(4));
|
||||
if (plain_data.empty())
|
||||
{
|
||||
throw std::runtime_error("Failed to decompress dump");
|
||||
}
|
||||
|
||||
utils::buffer_deserializer deserializer{plain_data, true};
|
||||
win_emu.deserialize(deserializer);
|
||||
}
|
||||
|
||||
void load_dump(windows_emulator& win_emu, const std::filesystem::path& dump)
|
||||
{
|
||||
std::vector<uint8_t> data{};
|
||||
if (!utils::io::read_file(dump, &data))
|
||||
{
|
||||
throw std::runtime_error("Failed to read dump file: " + dump.string());
|
||||
}
|
||||
|
||||
load_dump_data(win_emu, data);
|
||||
}
|
||||
|
||||
void watch_system_objects(windows_emulator& win_emu, const std::set<std::string, std::less<>>& modules,
|
||||
const bool cache_logging)
|
||||
{
|
||||
@@ -119,6 +57,23 @@ namespace
|
||||
#endif
|
||||
}
|
||||
|
||||
bool read_yes_no_answer()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const auto chr = static_cast<char>(getchar());
|
||||
if (chr == 'y')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (chr == 'n')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool run_emulation(windows_emulator& win_emu, const analysis_options& options)
|
||||
{
|
||||
std::atomic_uint32_t signals_received{0};
|
||||
@@ -153,20 +108,12 @@ namespace
|
||||
|
||||
if (signals_received > 0)
|
||||
{
|
||||
win_emu.log.log("Do you want to create a dump? (y/n)\n");
|
||||
win_emu.log.log("Do you want to create a snapshot? (y/n)\n");
|
||||
const auto write_snapshot = read_yes_no_answer();
|
||||
|
||||
bool write_dump = false;
|
||||
|
||||
char res{};
|
||||
while (res != 'n' && res != 'y')
|
||||
if (write_snapshot)
|
||||
{
|
||||
res = static_cast<char>(getchar());
|
||||
write_dump = res == 'y';
|
||||
}
|
||||
|
||||
if (write_dump)
|
||||
{
|
||||
generate_dump(win_emu);
|
||||
snapshot::write_emulator_snapshot(win_emu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,7 +201,7 @@ namespace
|
||||
}
|
||||
|
||||
auto win_emu = create_empty_emulator(options);
|
||||
load_dump(*win_emu, options.dump);
|
||||
snapshot::load_emulator_snapshot(*win_emu, options.dump);
|
||||
return win_emu;
|
||||
}
|
||||
|
||||
|
||||
123
src/analyzer/snapshot.cpp
Normal file
123
src/analyzer/snapshot.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "snapshot.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/compression.hpp>
|
||||
|
||||
namespace snapshot
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct snapshot_header
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
char magic[4] = {'S', 'N', 'A', 'P'};
|
||||
uint32_t version{1};
|
||||
};
|
||||
|
||||
static_assert(sizeof(snapshot_header) == 8);
|
||||
|
||||
std::span<const std::byte> validate_header(const std::span<const std::byte> snapshot)
|
||||
{
|
||||
snapshot_header default_header;
|
||||
snapshot_header header{};
|
||||
|
||||
if (snapshot.size() < sizeof(header))
|
||||
{
|
||||
throw std::runtime_error("Snapshot is too small");
|
||||
}
|
||||
|
||||
memcpy(&header, snapshot.data(), sizeof(header));
|
||||
|
||||
if (memcmp(default_header.magic, header.magic, sizeof(header.magic)) != 0)
|
||||
{
|
||||
throw std::runtime_error("Invalid snapshot");
|
||||
}
|
||||
|
||||
if (default_header.version != header.version)
|
||||
{
|
||||
throw std::runtime_error("Unsupported snapshot version: " + std::to_string(header.version) +
|
||||
"(needed: " + std::to_string(default_header.version) + ")");
|
||||
}
|
||||
|
||||
return snapshot.subspan(sizeof(header));
|
||||
}
|
||||
|
||||
std::vector<std::byte> get_compressed_emulator_state(const windows_emulator& win_emu)
|
||||
{
|
||||
utils::buffer_serializer serializer{};
|
||||
win_emu.serialize(serializer);
|
||||
|
||||
return utils::compression::zlib::compress(serializer.get_buffer());
|
||||
}
|
||||
|
||||
std::vector<std::byte> get_decompressed_emulator_state(const std::span<const std::byte> snapshot)
|
||||
{
|
||||
const auto data = validate_header(snapshot);
|
||||
return utils::compression::zlib::decompress(data);
|
||||
}
|
||||
|
||||
std::string get_main_executable_name(const windows_emulator& win_emu)
|
||||
{
|
||||
const auto* exe = win_emu.mod_manager.executable;
|
||||
if (exe)
|
||||
{
|
||||
return std::filesystem::path(exe->name).stem().string();
|
||||
}
|
||||
|
||||
return "process";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::byte> create_emulator_snapshot(const windows_emulator& win_emu)
|
||||
{
|
||||
const auto state = get_compressed_emulator_state(win_emu);
|
||||
|
||||
snapshot_header header{};
|
||||
std::span header_span(reinterpret_cast<const std::byte*>(&header), sizeof(header));
|
||||
|
||||
std::vector<std::byte> snapshot{};
|
||||
snapshot.reserve(header_span.size() + state.size());
|
||||
snapshot.assign(header_span.begin(), header_span.end());
|
||||
snapshot.insert(snapshot.end(), state.begin(), state.end());
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
std::filesystem::path write_emulator_snapshot(const windows_emulator& win_emu, const bool log)
|
||||
{
|
||||
std::filesystem::path snapshot_file =
|
||||
get_main_executable_name(win_emu) + "-" + std::to_string(time(nullptr)) + ".snap";
|
||||
|
||||
if (log)
|
||||
{
|
||||
win_emu.log.log("Writing snapshot to %s...\n", snapshot_file.string().c_str());
|
||||
}
|
||||
|
||||
const auto snapshot = create_emulator_snapshot(win_emu);
|
||||
if (!utils::io::write_file(snapshot_file, snapshot))
|
||||
{
|
||||
throw std::runtime_error("Failed to write snapshot!");
|
||||
}
|
||||
|
||||
return snapshot_file;
|
||||
}
|
||||
|
||||
void load_emulator_snapshot(windows_emulator& win_emu, const std::span<const std::byte> snapshot)
|
||||
{
|
||||
const auto data = get_decompressed_emulator_state(snapshot);
|
||||
|
||||
utils::buffer_deserializer deserializer{data};
|
||||
win_emu.deserialize(deserializer);
|
||||
}
|
||||
|
||||
void load_emulator_snapshot(windows_emulator& win_emu, const std::filesystem::path& snapshot_file)
|
||||
{
|
||||
std::vector<std::byte> data{};
|
||||
if (!utils::io::read_file(snapshot_file, &data))
|
||||
{
|
||||
throw std::runtime_error("Failed to read snapshot file: " + snapshot_file.string());
|
||||
}
|
||||
|
||||
load_emulator_snapshot(win_emu, data);
|
||||
}
|
||||
}
|
||||
12
src/analyzer/snapshot.hpp
Normal file
12
src/analyzer/snapshot.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows_emulator.hpp>
|
||||
|
||||
namespace snapshot
|
||||
{
|
||||
std::vector<std::byte> create_emulator_snapshot(const windows_emulator& win_emu);
|
||||
std::filesystem::path write_emulator_snapshot(const windows_emulator& win_emu, bool log = true);
|
||||
|
||||
void load_emulator_snapshot(windows_emulator& win_emu, std::span<const std::byte> snapshot);
|
||||
void load_emulator_snapshot(windows_emulator& win_emu, const std::filesystem::path& snapshot_file);
|
||||
}
|
||||
Reference in New Issue
Block a user