Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121// internal.cpp — status_str + shared file/error helpers.
#include "core/internal.hpp"#include "core/target.hpp"
#include <unicorn/unicorn.h>
#include <cstdint>#include <cstdio>#include <cstring>#include <span>#include <string>#include <vector>
namespace mf {
const char *status_str(Status s) noexcept { switch (s) { case Status::ok: return "ok"; case Status::argument: return "argument"; case Status::io: return "io"; case Status::emulator: return "emulator"; case Status::boot: return "boot"; case Status::budget: return "budget"; case Status::fault: return "fault"; case Status::unsupported: return "unsupported"; case Status::state: return "state"; case Status::resource: return "resource"; } return "?";}
namespace detail {
const char *uc_err_str(uc_err e) { const char *s = uc_strerror(e); return s != nullptr ? s : "unknown";}
bool unmapped_hook(HookCtx &ctx, uc_mem_type /*type*/, uint64_t address, int /*size*/, int64_t /*value*/) { if (ctx.policy == UnmapPolicy::fail) { return false; // not handled → Unicorn aborts the run } // uc_mem_map alone is enough: newly mapped memory is guaranteed // zero-filled — qemu_ram_alloc hosts come from qemu_anon_ram_alloc, // i.e. an anonymous mmap (POSIX) / VirtualAlloc MEM_COMMIT (Windows). // Verified against the vendored sources: uc_mem_map → memory_map → // memory_region_init_ram → qemu_ram_alloc (unicorn/qemu/exec.c, // util/oslib-posix.c). const uint64_t base = address & ~0xFFFFULL; const uc_err e = uc_mem_map(&ctx.uc(), base, 0x10000, UC_PROT_ALL); if (e != UC_ERR_OK) { // UC_ERR_MAP: the 64 KiB region overlaps an existing mapping // (fault near a mapped boundary, e.g. the flash hole above the // payload). uc_mem_map maps nothing in that case — returning // true would retry the access and spin forever, so report the // fault instead. return false; } if (ctx.counters != nullptr) { ctx.counters->unmapped_faults.fetch_add(1, std::memory_order_relaxed); } return true; // handled: continue after the access}
std::vector<std::byte> read_file(const std::string &path, size_t max_size) { FILE *f = std::fopen(path.c_str(), "rb"); if (f == nullptr) { throw Error{Status::io, "cannot open file"}; } std::fseek(f, 0, SEEK_END); long const file_size = std::ftell(f); std::fseek(f, 0, SEEK_SET); if (file_size < 0) { std::fclose(f); throw Error{Status::io, "bad file size"}; } auto sz = static_cast<size_t>(file_size); if (max_size > 0 && sz > max_size) { sz = max_size; } std::vector<std::byte> buf(sz); if (sz > 0 && std::fread(buf.data(), 1, sz, f) != sz) { std::fclose(f); throw Error{Status::io, "short read"}; } std::fclose(f); return buf;}
void write_file(const std::string &path, std::span<const std::byte> bytes) { FILE *f = std::fopen(path.c_str(), "wb"); if (f == nullptr) { throw Error{Status::io, "cannot create file"}; } if (!bytes.empty() && std::fwrite(bytes.data(), 1, bytes.size(), f) != bytes.size()) { std::fclose(f); throw Error{Status::io, "short write"}; } std::fclose(f);}
} // namespace detail
uc_err Target::emu_start(uint64_t begin, uint64_t until) { return ::uc_emu_start(uc_, begin, until, 0, 0);}
} // namespace mf