From 3391780c2f79ea754ba191bea9b3490b5a9803cf Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Fri, 4 Apr 2025 15:21:00 +0200 Subject: [PATCH 01/21] Disable exceptions for now --- src/samples/test-sample/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index a63db430..6cbf7349 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -417,8 +417,8 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_registry, "Registry") RUN_TEST(test_threads, "Threads") RUN_TEST(test_env, "Environment") - RUN_TEST(test_exceptions, "Exceptions") - RUN_TEST(test_native_exceptions, "Native Exceptions") + // RUN_TEST(test_exceptions, "Exceptions") + // RUN_TEST(test_native_exceptions, "Native Exceptions") RUN_TEST(test_tls, "TLS") RUN_TEST(test_socket, "Socket") From 3de9043299972f555017d359585f95a0f6e4e60a Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 09:23:38 +0200 Subject: [PATCH 02/21] Revert "Disable icicle tests" This reverts commit dd7a80a9f058b675dc9b3cd8d270bab8dcaea835. --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e2726cd..2afb2310 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -270,7 +270,7 @@ jobs: - macOS x86_64 emulator: - Unicorn - #- Icicle + - Icicle emulation-root: - Windows 2025 - Windows 2022 @@ -354,7 +354,7 @@ jobs: #- arm64-v8a emulator: - Unicorn - #- Icicle + - Icicle emulation-root: - Windows 2025 - Windows 2022 From 0fbb7a2e0dd6f2bf75b74582b74769c2564d9a1b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 09:28:01 +0200 Subject: [PATCH 03/21] Revert "Disable exceptions for now" This reverts commit 3391780c2f79ea754ba191bea9b3490b5a9803cf. --- src/samples/test-sample/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 6cbf7349..a63db430 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -417,8 +417,8 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_registry, "Registry") RUN_TEST(test_threads, "Threads") RUN_TEST(test_env, "Environment") - // RUN_TEST(test_exceptions, "Exceptions") - // RUN_TEST(test_native_exceptions, "Native Exceptions") + RUN_TEST(test_exceptions, "Exceptions") + RUN_TEST(test_native_exceptions, "Native Exceptions") RUN_TEST(test_tls, "TLS") RUN_TEST(test_socket, "Socket") From a336bdf2af0d6ee12b8cdab0efb29fbf7463655b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 10:01:28 +0200 Subject: [PATCH 04/21] Simplify violation hook API --- src/emulator/hook_interface.hpp | 8 +------- src/icicle-emulator/icicle_x64_emulator.cpp | 6 +----- src/unicorn-emulator/unicorn_x64_emulator.cpp | 5 ++--- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/emulator/hook_interface.hpp b/src/emulator/hook_interface.hpp index 39752398..01762b8f 100644 --- a/src/emulator/hook_interface.hpp +++ b/src/emulator/hook_interface.hpp @@ -53,8 +53,7 @@ class hook_interface public: virtual ~hook_interface() = default; - virtual emulator_hook* hook_memory_violation(uint64_t address, size_t size, - memory_violation_hook_callback callback) = 0; + virtual emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) = 0; virtual emulator_hook* hook_memory_access(uint64_t address, size_t size, memory_operation filter, complex_memory_hook_callback callback) = 0; @@ -67,11 +66,6 @@ class hook_interface virtual void delete_hook(emulator_hook* hook) = 0; - emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) - { - return this->hook_memory_violation(0, std::numeric_limits::max(), std::move(callback)); - } - emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback) { return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read); diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index d6fddef1..8de2594e 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -277,12 +277,8 @@ namespace icicle // throw std::runtime_error("Not implemented"); } - emulator_hook* hook_memory_violation(const uint64_t address, const size_t size, - memory_violation_hook_callback callback) override + emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) override { - (void)address; - (void)size; - auto obj = make_function_object(std::move(callback)); auto* ptr = obj.get(); auto* wrapper = diff --git a/src/unicorn-emulator/unicorn_x64_emulator.cpp b/src/unicorn-emulator/unicorn_x64_emulator.cpp index de01afcf..a91e44e5 100644 --- a/src/unicorn-emulator/unicorn_x64_emulator.cpp +++ b/src/unicorn-emulator/unicorn_x64_emulator.cpp @@ -537,8 +537,7 @@ namespace unicorn return result; } - emulator_hook* hook_memory_violation(uint64_t address, size_t size, - memory_violation_hook_callback callback) override + emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) override { function_wrapper wrapper( [c = std::move(callback), this](uc_engine*, const uc_mem_type type, const uint64_t address, @@ -573,7 +572,7 @@ namespace unicorn auto container = std::make_unique(); uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_INVALID, wrapper.get_function(), - wrapper.get_user_data(), address, size)); + wrapper.get_user_data(), 0, std::numeric_limits::max())); container->add(std::move(wrapper), std::move(hook)); From 349526a54ac91fdb783893be3002660a15095453 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 11:59:49 +0200 Subject: [PATCH 05/21] Simplify hooking interface --- src/analyzer/main.cpp | 12 +- src/analyzer/object_watching.hpp | 2 +- src/emulator/hook_interface.hpp | 43 +---- src/emulator/scoped_hook.hpp | 27 ++- src/fuzzer/main.cpp | 8 +- src/icicle-emulator/icicle_x64_emulator.cpp | 58 +++--- src/unicorn-emulator/unicorn_x64_emulator.cpp | 167 +++++++++--------- src/windows-emulator/windows_emulator.cpp | 6 +- src/windows-gdb-stub/x64_gdb_stub_handler.hpp | 88 ++++++--- 9 files changed, 226 insertions(+), 185 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index e72a3e3d..3c27000b 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -42,13 +42,15 @@ namespace win_emu.emu().hook_memory_write( win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters), 0x8, - [&win_emu, cache_logging, params_hook, modules](const uint64_t address, size_t, - const uint64_t value) mutable { + [&win_emu, cache_logging, params_hook, modules](const uint64_t address, const void*, size_t) mutable { const auto target_address = win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters); if (address == target_address) { - const emulator_object obj{win_emu.emu(), value}; + const emulator_object obj{ + win_emu.emu(), + win_emu.emu().read_memory(address), + }; win_emu.emu().delete_hook(params_hook); params_hook = watch_object(win_emu, modules, obj, cache_logging); @@ -236,7 +238,7 @@ namespace continue; } - auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) { + auto read_handler = [&, section, concise_logging](const uint64_t address, const void*, size_t) { const auto rip = win_emu->emu().read_instruction_pointer(); if (!win_emu->mod_manager.executable->is_within(rip)) { @@ -258,7 +260,7 @@ namespace section.name.c_str(), address, rip); }; - const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) { + const auto write_handler = [&, section, concise_logging](const uint64_t address, const void*, size_t) { const auto rip = win_emu->emu().read_instruction_pointer(); if (!win_emu->mod_manager.executable->is_within(rip)) { diff --git a/src/analyzer/object_watching.hpp b/src/analyzer/object_watching.hpp index 0ee5d3f1..df8ab871 100644 --- a/src/analyzer/object_watching.hpp +++ b/src/analyzer/object_watching.hpp @@ -11,7 +11,7 @@ emulator_hook* watch_object(windows_emulator& emu, const std::setname); diff --git a/src/emulator/hook_interface.hpp b/src/emulator/hook_interface.hpp index 01762b8f..96ae6195 100644 --- a/src/emulator/hook_interface.hpp +++ b/src/emulator/hook_interface.hpp @@ -40,11 +40,11 @@ using edge_generation_hook_callback = using basic_block_hook_callback = std::function; using instruction_hook_callback = std::function; - using interrupt_hook_callback = std::function; -using simple_memory_hook_callback = std::function; -using complex_memory_hook_callback = - std::function; + +using memory_access_hook_callback = std::function; +using memory_execution_hook_callback = std::function; + using memory_violation_hook_callback = std::function; @@ -53,43 +53,18 @@ class hook_interface public: virtual ~hook_interface() = default; - virtual emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) = 0; + virtual emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) = 0; + virtual emulator_hook* hook_memory_execution(uint64_t address, memory_execution_hook_callback callback) = 0; + virtual emulator_hook* hook_memory_read(uint64_t address, size_t size, memory_access_hook_callback callback) = 0; + virtual emulator_hook* hook_memory_write(uint64_t address, size_t size, memory_access_hook_callback callback) = 0; - virtual emulator_hook* hook_memory_access(uint64_t address, size_t size, memory_operation filter, - complex_memory_hook_callback callback) = 0; virtual emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) = 0; virtual emulator_hook* hook_interrupt(interrupt_hook_callback callback) = 0; + virtual emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) = 0; virtual emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) = 0; virtual emulator_hook* hook_basic_block(basic_block_hook_callback callback) = 0; virtual void delete_hook(emulator_hook* hook) = 0; - - emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback) - { - return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read); - } - - emulator_hook* hook_memory_write(const uint64_t address, const size_t size, simple_memory_hook_callback callback) - { - return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::write); - } - - emulator_hook* hook_memory_execution(const uint64_t address, const size_t size, - simple_memory_hook_callback callback) - { - return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::exec); - } - - private: - emulator_hook* hook_simple_memory_access(const uint64_t address, const size_t size, - simple_memory_hook_callback callback, const memory_operation operation) - { - assert((static_cast(operation) & (static_cast(operation) - 1)) == 0); - return this->hook_memory_access(address, size, operation, - [c = std::move(callback)](const uint64_t a, const size_t s, - const uint64_t value, - memory_operation) { c(a, s, value); }); - } }; diff --git a/src/emulator/scoped_hook.hpp b/src/emulator/scoped_hook.hpp index 188eeea3..6246b760 100644 --- a/src/emulator/scoped_hook.hpp +++ b/src/emulator/scoped_hook.hpp @@ -7,8 +7,13 @@ class scoped_hook scoped_hook() = default; scoped_hook(emulator& emu, emulator_hook* hook) + : scoped_hook(emu, std::vector{hook}) + { + } + + scoped_hook(emulator& emu, std::vector hooks) : emu_(&emu), - hook_(hook) + hooks_(std::move(hooks)) { } @@ -31,9 +36,9 @@ class scoped_hook { this->remove(); this->emu_ = obj.emu_; - this->hook_ = obj.hook_; + this->hooks_ = std::move(obj.hooks_); - obj.hook_ = {}; + obj.hooks_ = {}; } return *this; @@ -41,14 +46,22 @@ class scoped_hook void remove() { - if (this->hook_) + auto hooks = std::move(this->hooks_); + this->hooks_ = {}; + + for (auto* hook : hooks_) { - this->emu_->delete_hook(this->hook_); - this->hook_ = {}; + try + { + this->emu_->delete_hook(hook); + } + catch (...) + { + } } } private: emulator* emu_{}; - emulator_hook* hook_{}; + std::vector hooks_{}; }; diff --git a/src/fuzzer/main.cpp b/src/fuzzer/main.cpp index 9c10eee1..237d357c 100644 --- a/src/fuzzer/main.cpp +++ b/src/fuzzer/main.cpp @@ -35,7 +35,9 @@ namespace void forward_emulator(windows_emulator& win_emu) { const auto target = win_emu.mod_manager.executable->find_export("vulnerable"); - win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t) { win_emu.emu().stop(); }); + win_emu.emu().hook_memory_execution(target, [&](uint64_t) { + win_emu.emu().stop(); // + }); run_emulation(win_emu); } @@ -64,7 +66,9 @@ namespace const auto ret = emu.emu().read_stack(0); - emu.emu().hook_memory_execution(ret, 1, [&](uint64_t, size_t, uint64_t) { emu.emu().stop(); }); + emu.emu().hook_memory_execution(ret, [&](uint64_t) { + emu.emu().stop(); // + }); } void restore_emulator() diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index 8de2594e..071543df 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -298,36 +298,46 @@ namespace icicle return wrap_hook(id); } - emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter, - complex_memory_hook_callback callback) override + emulator_hook* hook_memory_execution(const uint64_t address, memory_execution_hook_callback callback) override { - if (filter == memory_permission::none) - { - return nullptr; - } + // TODO + (void)address; + throw std::runtime_error("Not implemented"); + } - const auto shared_callback = std::make_shared(std::move(callback)); + emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override + { + auto wrapper = make_function_object(std::move(callback)); + auto* ptr = wrapper.get(); + auto* func = +[](void* user, const uint64_t addr) { + auto& func = *static_cast(user); + (func)(addr); + }; - if ((filter & memory_permission::exec) == memory_permission::exec) - { - if (address != 0 || size != std::numeric_limits::max()) - { - throw std::runtime_error("Not supported!"); - } + const auto id = icicle_add_execution_hook(this->emu_, func, ptr); + this->hooks_[id] = std::move(wrapper); - auto* ptr = shared_callback.get(); - auto wrapper = wrap_shared(shared_callback); - auto* func = +[](void* user, const uint64_t ptr) { - (*static_cast(user))(ptr, 0, 0, memory_permission::exec); - }; + return wrap_hook(id); + } - const auto id = icicle_add_execution_hook(this->emu_, func, ptr); - this->hooks_[id] = std::move(wrapper); + emulator_hook* hook_memory_read(const uint64_t address, const size_t size, + memory_access_hook_callback callback) override + { + // TODO + (void)address; + (void)size; + (void)callback; + throw std::runtime_error("Not implemented"); + } - return wrap_hook(id); - } - - return nullptr; + emulator_hook* hook_memory_write(const uint64_t address, const size_t size, + const memory_access_hook_callback callback) override + { + // TODO + (void)address; + (void)size; + (void)callback; + throw std::runtime_error("Not implemented"); } void delete_hook(emulator_hook* hook) override diff --git a/src/unicorn-emulator/unicorn_x64_emulator.cpp b/src/unicorn-emulator/unicorn_x64_emulator.cpp index a91e44e5..1e18be59 100644 --- a/src/unicorn-emulator/unicorn_x64_emulator.cpp +++ b/src/unicorn-emulator/unicorn_x64_emulator.cpp @@ -175,63 +175,6 @@ namespace unicorn size_t size_{}; }; - void add_read_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, - const std::shared_ptr& callback) - { - function_wrapper wrapper( - [callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, const int64_t) { - const auto operation = map_memory_operation(type); - if (operation != memory_permission::none) - { - (*callback)(address, static_cast(size), 0, operation); - } - }); - - unicorn_hook hook{uc}; - - uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_MEM_READ, wrapper.get_function(), - wrapper.get_user_data(), address, address + size)); - - container.add(std::move(wrapper), std::move(hook)); - } - - void add_write_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, - const std::shared_ptr& callback) - { - function_wrapper wrapper( - [callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, - const uint64_t value) { - const auto operation = map_memory_operation(type); - if (operation != memory_permission::none) - { - (*callback)(address, static_cast(size), value, operation); - } - }); - - unicorn_hook hook{uc}; - - uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_MEM_WRITE, wrapper.get_function(), - wrapper.get_user_data(), address, address + size)); - - container.add(std::move(wrapper), std::move(hook)); - } - - void add_exec_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, - const std::shared_ptr& callback) - { - function_wrapper wrapper( - [callback](uc_engine*, const uint64_t address, const uint32_t size) { - (*callback)(address, size, 0, memory_permission::exec); - }); - - unicorn_hook hook{uc}; - - uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(), wrapper.get_user_data(), - address, address + size)); - - container.add(std::move(wrapper), std::move(hook)); - } - basic_block map_block(const uc_tb& translation_block) { basic_block block{}; @@ -581,38 +524,94 @@ namespace unicorn return result; } - emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter, - complex_memory_hook_callback callback) override + emulator_hook* hook_memory_execution(uint64_t address, uint64_t size, + memory_execution_hook_callback callback) { - if (filter == memory_permission::none) - { - return nullptr; - } + auto exec_wrapper = [c = std::move(callback)](uc_engine*, const uint64_t address, + const uint32_t /*size*/) { + c(address); // + }; - const auto shared_callback = std::make_shared(std::move(callback)); + function_wrapper wrapper(std::move(exec_wrapper)); + unicorn_hook hook{*this}; + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(), + wrapper.get_user_data(), address, address + size)); + + auto* container = this->create_hook_container(); + container->add(std::move(wrapper), std::move(hook)); + return container->as_opaque_hook(); + } + + emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override + { + return this->hook_memory_execution(0, std::numeric_limits::max(), std::move(callback)); + } + + emulator_hook* hook_memory_execution(const uint64_t address, + memory_execution_hook_callback callback) override + { + return this->hook_memory_execution(address, 1, std::move(callback)); + } + + emulator_hook* hook_memory_read(uint64_t address, size_t size, + memory_access_hook_callback callback) override + { + auto read_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type, + const uint64_t address, const int size, + const uint64_t value) { + const auto operation = map_memory_operation(type); + if (operation != memory_permission::none && size > 0) + { + c(address, &value, std::min(static_cast(size), sizeof(value))); + } + }; + + function_wrapper wrapper( + std::move(read_wrapper)); + + unicorn_hook hook{*this}; + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_READ_AFTER, wrapper.get_function(), + wrapper.get_user_data(), address, address + size)); + + auto* container = this->create_hook_container(); + container->add(std::move(wrapper), std::move(hook)); + return container->as_opaque_hook(); + } + + emulator_hook* hook_memory_write(uint64_t address, size_t size, + memory_access_hook_callback callback) override + { + auto write_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type, + const uint64_t address, const int size, + const uint64_t value) { + const auto operation = map_memory_operation(type); + if (operation != memory_permission::none && size > 0) + { + c(address, &value, std::min(static_cast(size), sizeof(value))); + } + }; + + function_wrapper wrapper( + std::move(write_wrapper)); + + unicorn_hook hook{*this}; + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_WRITE, wrapper.get_function(), + wrapper.get_user_data(), address, address + size)); + + auto* container = this->create_hook_container(); + container->add(std::move(wrapper), std::move(hook)); + return container->as_opaque_hook(); + } + + hook_container* create_hook_container() + { auto container = std::make_unique(); - - if ((filter & memory_operation::read) != memory_operation::none) - { - add_read_hook(*this, address, size, *container, shared_callback); - } - - if ((filter & memory_operation::write) != memory_operation::none) - { - add_write_hook(*this, address, size, *container, shared_callback); - } - - if ((filter & memory_operation::exec) != memory_operation::none) - { - add_exec_hook(*this, address, size, *container, shared_callback); - } - - auto* result = container->as_opaque_hook(); - + auto* ptr = container.get(); this->hooks_.push_back(std::move(container)); - - return result; + return ptr; } void delete_hook(emulator_hook* hook) override diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index b9abddab..9b200b63 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -517,9 +517,9 @@ void windows_emulator::setup_hooks() return memory_violation_continuation::resume; }); - this->emu().hook_memory_execution( - 0, std::numeric_limits::max(), - [&](const uint64_t address, const size_t, const uint64_t) { this->on_instruction_execution(address); }); + this->emu().hook_memory_execution([&](const uint64_t address) { + this->on_instruction_execution(address); // + }); } void windows_emulator::start(size_t count) diff --git a/src/windows-gdb-stub/x64_gdb_stub_handler.hpp b/src/windows-gdb-stub/x64_gdb_stub_handler.hpp index 6fedb346..aa519acd 100644 --- a/src/windows-gdb-stub/x64_gdb_stub_handler.hpp +++ b/src/windows-gdb-stub/x64_gdb_stub_handler.hpp @@ -8,26 +8,6 @@ #include "x64_register_mapping.hpp" #include "x64_target_descriptions.hpp" -inline memory_operation map_breakpoint_type(const gdb_stub::breakpoint_type type) -{ - using enum gdb_stub::breakpoint_type; - - switch (type) - { - case software: - case hardware_exec: - return memory_operation::exec; - case hardware_read: - return memory_permission::read; - case hardware_write: - return memory_permission::write; - case hardware_read_write: - return memory_permission::read_write; - default: - throw std::runtime_error("Bad bp type"); - } -} - struct breakpoint_key { size_t addr{}; @@ -196,11 +176,9 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler try { return this->hooks_.access([&](hook_map& hooks) { - hooks[{addr, size, type}] = scoped_hook( - *this->emu_, this->emu_->hook_memory_access(addr, size, map_breakpoint_type(type), - [this](uint64_t, size_t, uint64_t, memory_operation) { - this->on_interrupt(); // - })); + auto hook_vector = this->create_hook(type, addr, size); + + hooks[{addr, size, type}] = scoped_hook(*this->emu_, std::move(hook_vector)); return true; }); @@ -264,4 +242,64 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler using hook_map = std::unordered_map; utils::concurrency::container hooks_{}; + + std::vector create_execute_hook(const uint64_t addr, const size_t size) + { + std::vector hooks{}; + hooks.reserve(size); + + for (size_t i = 0; i < size; ++i) + { + auto* hook = this->emu_->hook_memory_execution(addr + i, [this](const uint64_t) { + this->on_interrupt(); // + }); + + hooks.push_back(hook); + } + + return hooks; + } + + std::vector create_read_hook(const uint64_t addr, const size_t size) + { + auto* hook = this->emu_->hook_memory_read(addr, size, [this](const uint64_t, const void*, const size_t) { + this->on_interrupt(); // + }); + + return {hook}; + } + + std::vector create_write_hook(const uint64_t addr, const size_t size) + { + auto* hook = this->emu_->hook_memory_write(addr, size, [this](const uint64_t, const void*, const size_t) { + this->on_interrupt(); // + }); + + return {hook}; + } + + std::vector create_hook(const gdb_stub::breakpoint_type type, const uint64_t addr, + const size_t size) + { + using enum gdb_stub::breakpoint_type; + + switch (type) + { + case software: + case hardware_exec: + return this->create_execute_hook(addr, size); + case hardware_read: + return this->create_read_hook(addr, size); + case hardware_write: + return this->create_write_hook(addr, size); + case hardware_read_write: { + auto hooks1 = this->create_hook(hardware_read, addr, size); + auto hooks2 = this->create_hook(hardware_write, addr, size); + hooks1.insert(hooks1.end(), hooks2.begin(), hooks2.end()); + return hooks1; + } + default: + throw std::runtime_error("Bad bp type"); + } + } }; From 638ad2c7a45d0ebfd8851cecd2d24d16bfee0ae4 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 12:51:37 +0200 Subject: [PATCH 06/21] Support read and write hooks --- src/icicle-emulator/icicle_x64_emulator.cpp | 74 ++++++++++----------- src/icicle/src/icicle.rs | 68 +++++++++++++++---- src/icicle/src/lib.rs | 27 +++++++- 3 files changed, 119 insertions(+), 50 deletions(-) diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index 071543df..6ab52138 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -7,13 +7,14 @@ using icicle_emulator = struct icicle_emulator_; extern "C" { + using icicle_mmio_read_func = void(void* user, uint64_t address, void* data, size_t length); + using icicle_mmio_write_func = void(void* user, uint64_t address, const void* data, size_t length); + using raw_func = void(void*); using ptr_func = void(void*, uint64_t); using violation_func = int32_t(void*, uint64_t address, uint8_t operation, int32_t unmapped); using data_accessor_func = void(void* user, const void* data, size_t length); - - using icicle_mmio_read_func = void(void* user, uint64_t address, void* data, size_t length); - using icicle_mmio_write_func = void(void* user, uint64_t address, const void* data, size_t length); + using memory_access_func = icicle_mmio_write_func; icicle_emulator* icicle_create_emulator(); int32_t icicle_protect_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions); @@ -28,7 +29,9 @@ extern "C" uint32_t icicle_add_syscall_hook(icicle_emulator*, raw_func* callback, void* data); uint32_t icicle_add_execution_hook(icicle_emulator*, ptr_func* callback, void* data); uint32_t icicle_add_violation_hook(icicle_emulator*, violation_func* callback, void* data); - void icicle_remove_syscall_hook(icicle_emulator*, uint32_t id); + uint32_t icicle_add_read_hook(icicle_emulator*, uint64_t start, uint64_t end, memory_access_func* cb, void* data); + uint32_t icicle_add_write_hook(icicle_emulator*, uint64_t start, uint64_t end, memory_access_func* cb, void* data); + void icicle_remove_hook(icicle_emulator*, uint32_t id); size_t icicle_read_register(icicle_emulator*, int reg, void* data, size_t length); size_t icicle_write_register(icicle_emulator*, int reg, const void* data, size_t length); void icicle_start(icicle_emulator*, size_t count); @@ -77,21 +80,6 @@ namespace icicle { return std::make_unique>(std::move(func)); } - - template - std::unique_ptr wrap_shared(std::shared_ptr shared_ptr) - { - struct shard_wrapper : utils::object - { - std::shared_ptr ptr{}; - ~shard_wrapper() override = default; - }; - - auto wrapper = std::make_unique(); - wrapper->ptr = std::move(shared_ptr); - - return wrapper; - } } class icicle_x64_emulator : public x64_emulator @@ -307,15 +295,15 @@ namespace icicle emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override { - auto wrapper = make_function_object(std::move(callback)); - auto* ptr = wrapper.get(); - auto* func = +[](void* user, const uint64_t addr) { - auto& func = *static_cast(user); + auto object = make_function_object(std::move(callback)); + auto* ptr = object.get(); + auto* wrapper = +[](void* user, const uint64_t addr) { + auto& func = *static_cast(user); (func)(addr); }; - const auto id = icicle_add_execution_hook(this->emu_, func, ptr); - this->hooks_[id] = std::move(wrapper); + const auto id = icicle_add_execution_hook(this->emu_, wrapper, ptr); + this->hooks_[id] = std::move(object); return wrap_hook(id); } @@ -323,21 +311,33 @@ namespace icicle emulator_hook* hook_memory_read(const uint64_t address, const size_t size, memory_access_hook_callback callback) override { - // TODO - (void)address; - (void)size; - (void)callback; - throw std::runtime_error("Not implemented"); + auto obj = make_function_object(std::move(callback)); + auto* ptr = obj.get(); + auto* wrapper = +[](void* user, const uint64_t address, const void* data, size_t length) { + const auto& func = *static_cast(user); + func(address, data, length); + }; + + const auto id = icicle_add_read_hook(this->emu_, address, address + size, wrapper, ptr); + this->hooks_[id] = std::move(obj); + + return wrap_hook(id); } emulator_hook* hook_memory_write(const uint64_t address, const size_t size, - const memory_access_hook_callback callback) override + memory_access_hook_callback callback) override { - // TODO - (void)address; - (void)size; - (void)callback; - throw std::runtime_error("Not implemented"); + auto obj = make_function_object(std::move(callback)); + auto* ptr = obj.get(); + auto* wrapper = +[](void* user, const uint64_t address, const void* data, size_t length) { + const auto& func = *static_cast(user); + func(address, data, length); + }; + + const auto id = icicle_add_write_hook(this->emu_, address, address + size, wrapper, ptr); + this->hooks_[id] = std::move(obj); + + return wrap_hook(id); } void delete_hook(emulator_hook* hook) override @@ -349,7 +349,7 @@ namespace icicle return; } - icicle_remove_syscall_hook(this->emu_, id); + icicle_remove_hook(this->emu_, id); this->hooks_.erase(entry); } diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index 292c4fd3..3582ca63 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -1,5 +1,5 @@ -use icicle_cpu::ValueSource; use icicle_cpu::ExceptionCode; +use icicle_cpu::ValueSource; use std::{cell::RefCell, collections::HashMap, rc::Rc}; use crate::registers; @@ -123,10 +123,7 @@ impl icicle_vm::CodeInjector for InstructionHookInjector { } } - std::mem::swap( - &mut tmp_block.instructions, - &mut block.pcode.instructions, - ); + std::mem::swap(&mut tmp_block.instructions, &mut block.pcode.instructions); } } } @@ -139,6 +136,22 @@ pub struct IcicleEmulator { execution_hooks: Rc>>, } +struct MemoryHook { + callback: Box, +} + +impl icicle_cpu::mem::WriteHook for MemoryHook { + fn write(&mut self, _mem: &mut icicle_cpu::Mmu, addr: u64, value: &[u8]) { + (self.callback)(addr, value); + } +} + +impl icicle_cpu::mem::ReadAfterHook for MemoryHook { + fn read(&mut self, _mem: &mut icicle_cpu::Mmu, addr: u64, value: &[u8]) { + (self.callback)(addr, value); + } +} + pub struct MmioHandler { read_handler: Box, write_handler: Box, @@ -171,7 +184,8 @@ impl icicle_cpu::mem::IoMemory for MmioHandler { impl IcicleEmulator { pub fn new() -> Self { let mut virtual_machine = create_x64_vm(); - let exec_hooks: Rc>> = Rc::new(RefCell::new(HookContainer::new())); + let exec_hooks: Rc>> = + Rc::new(RefCell::new(HookContainer::new())); let exec_hooks_clone = Rc::clone(&exec_hooks); @@ -211,9 +225,9 @@ impl IcicleEmulator { icicle_vm::VmExit::UnhandledException((code, value)) => { let continue_execution = self.handle_exception(code, value); if !continue_execution { - break + break; } - }, + } _ => break, }; } @@ -227,7 +241,7 @@ impl IcicleEmulator { ExceptionCode::ReadUnmapped => self.handle_violation(value, FOREIGN_READ, true), ExceptionCode::WriteUnmapped => self.handle_violation(value, FOREIGN_WRITE, true), ExceptionCode::ExecViolation => self.handle_violation(value, FOREIGN_EXEC, true), - _ => false + _ => false, }; return continue_execution; @@ -242,13 +256,13 @@ impl IcicleEmulator { let mut continue_execution = true; for (_key, func) in self.violation_hooks.get_hooks() { - continue_execution &= func(address, permission, unmapped ); + continue_execution &= func(address, permission, unmapped); } return continue_execution; } - fn handle_syscall(&mut self) -> bool{ + fn handle_syscall(&mut self) -> bool { for (_key, func) in self.syscall_hooks.get_hooks() { func(); } @@ -258,7 +272,7 @@ impl IcicleEmulator { } pub fn stop(&mut self) { - self.vm.icount_limit = 0; + self.vm.icount_limit = 0; } pub fn add_violation_hook(&mut self, callback: Box bool>) -> u32 { @@ -276,6 +290,34 @@ impl IcicleEmulator { return qualify_hook_id(hook_id, HookType::Syscall); } + pub fn add_read_hook( + &mut self, + start: u64, + end: u64, + callback: Box, + ) -> u32 { + let id = self.get_mem().add_read_after_hook(start, end, Box::new(MemoryHook { callback })); + if id.is_none() { + return 0; + } + + return qualify_hook_id(id.expect("Hook id needed"), HookType::Read); + } + + pub fn add_write_hook( + &mut self, + start: u64, + end: u64, + callback: Box, + ) -> u32 { + let id = self.get_mem().add_write_hook(start, end, Box::new(MemoryHook { callback })); + if id.is_none() { + return 0; + } + + return qualify_hook_id(id.expect("Hook id needed"), HookType::Write); + } + pub fn remove_hook(&mut self, id: u32) { let (hook_id, hook_type) = split_hook_id(id); @@ -283,6 +325,8 @@ impl IcicleEmulator { HookType::Syscall => self.syscall_hooks.remove_hook(hook_id), HookType::Violation => self.violation_hooks.remove_hook(hook_id), HookType::Execute => self.execution_hooks.borrow_mut().remove_hook(hook_id), + HookType::Read => {self.get_mem().remove_read_after_hook(hook_id);()}, + HookType::Write => {self.get_mem().remove_write_hook(hook_id);()}, _ => {} } } diff --git a/src/icicle/src/lib.rs b/src/icicle/src/lib.rs index dab13cfb..655f83ca 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -41,6 +41,7 @@ type DataFunction = extern "C" fn(*mut c_void, *const c_void, usize); type MmioReadFunction = extern "C" fn(*mut c_void, u64, *mut c_void, usize); type MmioWriteFunction = extern "C" fn(*mut c_void, u64, *const c_void, usize); type ViolationFunction = extern "C" fn(*mut c_void, u64, u8, i32) -> i32; +type MemoryAccessFunction = MmioWriteFunction; #[unsafe(no_mangle)] pub fn icicle_map_mmio( @@ -181,6 +182,30 @@ pub fn icicle_add_violation_hook(ptr: *mut c_void, callback: ViolationFunction, } } +#[unsafe(no_mangle)] +pub fn icicle_add_read_hook(ptr: *mut c_void, start: u64, end: u64, callback: MemoryAccessFunction, user: *mut c_void) -> u32 { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + return emulator.add_read_hook(start, end, Box::new( + move |address: u64, data: &[u8]| { + callback(user, address, data.as_ptr() as *const c_void, data.len()); + }, + )); + } +} + +#[unsafe(no_mangle)] +pub fn icicle_add_write_hook(ptr: *mut c_void, start: u64, end: u64, callback: MemoryAccessFunction, user: *mut c_void) -> u32 { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + return emulator.add_write_hook(start, end, Box::new( + move |address: u64, data: &[u8]| { + callback(user, address, data.as_ptr() as *const c_void, data.len()); + }, + )); + } +} + #[unsafe(no_mangle)] pub fn icicle_add_syscall_hook(ptr: *mut c_void, callback: RawFunction, data: *mut c_void) -> u32 { unsafe { @@ -198,7 +223,7 @@ pub fn icicle_add_execution_hook(ptr: *mut c_void, callback: PtrFunction, data: } #[unsafe(no_mangle)] -pub fn icicle_remove_syscall_hook(ptr: *mut c_void, id: u32) { +pub fn icicle_remove_hook(ptr: *mut c_void, id: u32) { unsafe { let emulator = &mut *(ptr as *mut IcicleEmulator); emulator.remove_hook(id); From efe5a21e575587c659016cf10f4af6b676e4991e Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 14:50:11 +0200 Subject: [PATCH 07/21] Switch to icicle fork --- src/icicle/Cargo.lock | 42 +++++++++++++++++++++--------------------- src/icicle/Cargo.toml | 6 +++--- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/icicle/Cargo.lock b/src/icicle/Cargo.lock index 93451e3b..1bead747 100644 --- a/src/icicle/Cargo.lock +++ b/src/icicle/Cargo.lock @@ -278,9 +278,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -294,9 +294,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "miniz_oxide", @@ -370,7 +370,7 @@ dependencies = [ [[package]] name = "icicle-cpu" version = "0.1.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" dependencies = [ "addr2line", "ahash", @@ -390,7 +390,7 @@ dependencies = [ [[package]] name = "icicle-jit" version = "0.2.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" dependencies = [ "cranelift", "cranelift-codegen", @@ -408,7 +408,7 @@ dependencies = [ [[package]] name = "icicle-linux" version = "0.1.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" dependencies = [ "bitflags 2.9.0", "bstr", @@ -424,7 +424,7 @@ dependencies = [ [[package]] name = "icicle-mem" version = "0.3.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" dependencies = [ "tracing", ] @@ -432,7 +432,7 @@ dependencies = [ [[package]] name = "icicle-vm" version = "0.2.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" dependencies = [ "anyhow", "icicle-cpu", @@ -458,9 +458,9 @@ checksum = "365a784774bb381e8c19edb91190a90d7f2625e057b55de2bc0f6b57bc779ff2" [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -519,9 +519,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" dependencies = [ "adler2", ] @@ -542,14 +542,14 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "pcode" version = "0.2.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" [[package]] name = "pin-project-lite" @@ -681,7 +681,7 @@ dependencies = [ [[package]] name = "sleigh-compile" version = "0.3.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" dependencies = [ "pcode", "serde", @@ -694,12 +694,12 @@ dependencies = [ [[package]] name = "sleigh-parse" version = "0.3.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" [[package]] name = "sleigh-runtime" version = "0.1.0" -source = "git+https://github.com/icicle-emu/icicle-emu#6e9fd3e34aec440ac92c1f49f4a70fc288949de9" +source = "git+https://github.com/momo5502/icicle-emu#ec78c91d68d0e724d2e9225778a33e447bb0d960" dependencies = [ "pcode", "sleigh-parse", @@ -713,9 +713,9 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "stable_deref_trait" diff --git a/src/icicle/Cargo.toml b/src/icicle/Cargo.toml index 8019c2b2..f74bf4cf 100644 --- a/src/icicle/Cargo.toml +++ b/src/icicle/Cargo.toml @@ -7,6 +7,6 @@ edition = "2024" crate-type = ["staticlib"] [dependencies] -icicle-vm = { git = "https://github.com/icicle-emu/icicle-emu" } -icicle-cpu = { git = "https://github.com/icicle-emu/icicle-emu" } -pcode = { git = "https://github.com/icicle-emu/icicle-emu" } +icicle-vm = { git = "https://github.com/momo5502/icicle-emu" } +icicle-cpu = { git = "https://github.com/momo5502/icicle-emu" } +pcode = { git = "https://github.com/momo5502/icicle-emu" } From 3978eeed2a8d804ef577c700419cc70d979f8406 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 15:28:14 +0200 Subject: [PATCH 08/21] Finish execution hook support --- src/icicle-emulator/icicle_x64_emulator.cpp | 19 +++-- src/icicle/src/icicle.rs | 90 ++++++++++++++++++--- src/icicle/src/lib.rs | 12 ++- 3 files changed, 101 insertions(+), 20 deletions(-) diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index 6ab52138..77101bc5 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -27,7 +27,8 @@ extern "C" int32_t icicle_save_registers(icicle_emulator*, data_accessor_func* accessor, void* accessor_data); int32_t icicle_restore_registers(icicle_emulator*, const void* data, size_t length); uint32_t icicle_add_syscall_hook(icicle_emulator*, raw_func* callback, void* data); - uint32_t icicle_add_execution_hook(icicle_emulator*, ptr_func* callback, void* data); + uint32_t icicle_add_execution_hook(icicle_emulator*, uint64_t address, ptr_func* callback, void* data); + uint32_t icicle_add_generic_execution_hook(icicle_emulator*, ptr_func* callback, void* data); uint32_t icicle_add_violation_hook(icicle_emulator*, violation_func* callback, void* data); uint32_t icicle_add_read_hook(icicle_emulator*, uint64_t start, uint64_t end, memory_access_func* cb, void* data); uint32_t icicle_add_write_hook(icicle_emulator*, uint64_t start, uint64_t end, memory_access_func* cb, void* data); @@ -288,9 +289,17 @@ namespace icicle emulator_hook* hook_memory_execution(const uint64_t address, memory_execution_hook_callback callback) override { - // TODO - (void)address; - throw std::runtime_error("Not implemented"); + auto object = make_function_object(std::move(callback)); + auto* ptr = object.get(); + auto* wrapper = +[](void* user, const uint64_t addr) { + auto& func = *static_cast(user); + (func)(addr); + }; + + const auto id = icicle_add_execution_hook(this->emu_, address, wrapper, ptr); + this->hooks_[id] = std::move(object); + + return wrap_hook(id); } emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override @@ -302,7 +311,7 @@ namespace icicle (func)(addr); }; - const auto id = icicle_add_execution_hook(this->emu_, wrapper, ptr); + const auto id = icicle_add_generic_execution_hook(this->emu_, wrapper, ptr); this->hooks_[id] = std::move(object); return wrap_hook(id); diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index 3582ca63..05daf8ae 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -46,7 +46,8 @@ enum HookType { Syscall = 1, Read, Write, - Execute, + ExecuteGeneric, + ExecuteSpecific, Violation, Unknown, } @@ -128,12 +129,72 @@ impl icicle_vm::CodeInjector for InstructionHookInjector { } } +struct ExecutionHooks { + generic_hooks: HookContainer, + specific_hooks: HookContainer, + address_mapping: HashMap>, +} + +impl ExecutionHooks { + pub fn new() -> Self { + Self { + generic_hooks: HookContainer::new(), + specific_hooks: HookContainer::new(), + address_mapping: HashMap::new(), + } + } + + pub fn execute(&self, address: u64) { + for (_key, func) in self.generic_hooks.get_hooks() { + func(address); + } + + let mapping = self.address_mapping.get(&address); + if mapping.is_none(){ + return; + } + + for id in mapping.unwrap() { + let func = self.specific_hooks.get_hooks().get(&id); + if func.is_some() { + func.unwrap()(address); + } + } + } + + pub fn add_generic_hook(&mut self, callback: Box) -> u32 { + self.generic_hooks.add_hook(callback) + } + + pub fn add_specific_hook(&mut self, address: u64, callback: Box) -> u32 { + let id = self.specific_hooks.add_hook(callback); + + let mapping = self.address_mapping.entry(address).or_insert_with(Vec::new); + mapping.push(id); + + return id; + } + + pub fn remove_generic_hook(&mut self, id: u32) { + self.generic_hooks.remove_hook(id); + } + + pub fn remove_specific_hook(&mut self, id: u32) { + self.address_mapping.retain(|_, vec| { + vec.retain(|&x| x != id); + !vec.is_empty() + }); + + self.specific_hooks.remove_hook(id); + } +} + pub struct IcicleEmulator { vm: icicle_vm::Vm, reg: registers::X64RegisterNodes, syscall_hooks: HookContainer, violation_hooks: HookContainer bool>, - execution_hooks: Rc>>, + execution_hooks: Rc>, } struct MemoryHook { @@ -184,15 +245,12 @@ impl icicle_cpu::mem::IoMemory for MmioHandler { impl IcicleEmulator { pub fn new() -> Self { let mut virtual_machine = create_x64_vm(); - let exec_hooks: Rc>> = - Rc::new(RefCell::new(HookContainer::new())); + let exec_hooks = Rc::new(RefCell::new(ExecutionHooks::new())); let exec_hooks_clone = Rc::clone(&exec_hooks); let hook = icicle_cpu::InstHook::new(move |_: &mut icicle_cpu::Cpu, addr: u64| { - for (_key, func) in exec_hooks_clone.borrow().get_hooks() { - func(addr); - } + exec_hooks_clone.borrow().execute(addr); }); let hook = virtual_machine.cpu.add_hook(hook); @@ -279,10 +337,15 @@ impl IcicleEmulator { let hook_id = self.violation_hooks.add_hook(callback); return qualify_hook_id(hook_id, HookType::Violation); } + + pub fn add_execution_hook(&mut self, address:u64, callback: Box) -> u32 { + let hook_id = self.execution_hooks.borrow_mut().add_specific_hook(address, callback); + return qualify_hook_id(hook_id, HookType::ExecuteSpecific); + } - pub fn add_execution_hook(&mut self, callback: Box) -> u32 { - let hook_id = self.execution_hooks.borrow_mut().add_hook(callback); - return qualify_hook_id(hook_id, HookType::Execute); + pub fn add_generic_execution_hook(&mut self, callback: Box) -> u32 { + let hook_id = self.execution_hooks.borrow_mut().add_generic_hook(callback); + return qualify_hook_id(hook_id, HookType::ExecuteGeneric); } pub fn add_syscall_hook(&mut self, callback: Box) -> u32 { @@ -301,7 +364,7 @@ impl IcicleEmulator { return 0; } - return qualify_hook_id(id.expect("Hook id needed"), HookType::Read); + return qualify_hook_id(id.unwrap(), HookType::Read); } pub fn add_write_hook( @@ -315,7 +378,7 @@ impl IcicleEmulator { return 0; } - return qualify_hook_id(id.expect("Hook id needed"), HookType::Write); + return qualify_hook_id(id.unwrap(), HookType::Write); } pub fn remove_hook(&mut self, id: u32) { @@ -324,7 +387,8 @@ impl IcicleEmulator { match hook_type { HookType::Syscall => self.syscall_hooks.remove_hook(hook_id), HookType::Violation => self.violation_hooks.remove_hook(hook_id), - HookType::Execute => self.execution_hooks.borrow_mut().remove_hook(hook_id), + HookType::ExecuteGeneric => self.execution_hooks.borrow_mut().remove_generic_hook(hook_id), + HookType::ExecuteSpecific => self.execution_hooks.borrow_mut().remove_specific_hook(hook_id), HookType::Read => {self.get_mem().remove_read_after_hook(hook_id);()}, HookType::Write => {self.get_mem().remove_write_hook(hook_id);()}, _ => {} diff --git a/src/icicle/src/lib.rs b/src/icicle/src/lib.rs index 655f83ca..a494b806 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -215,10 +215,18 @@ pub fn icicle_add_syscall_hook(ptr: *mut c_void, callback: RawFunction, data: *m } #[unsafe(no_mangle)] -pub fn icicle_add_execution_hook(ptr: *mut c_void, callback: PtrFunction, data: *mut c_void) -> u32 { +pub fn icicle_add_generic_execution_hook(ptr: *mut c_void, callback: PtrFunction, data: *mut c_void) -> u32 { unsafe { let emulator = &mut *(ptr as *mut IcicleEmulator); - return emulator.add_execution_hook(Box::new(move |ptr: u64| callback(data, ptr))); + return emulator.add_generic_execution_hook(Box::new(move |ptr: u64| callback(data, ptr))); + } +} + +#[unsafe(no_mangle)] +pub fn icicle_add_execution_hook(ptr: *mut c_void, address: u64, callback: PtrFunction, data: *mut c_void) -> u32 { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + return emulator.add_execution_hook(address, Box::new(move |ptr: u64| callback(data, ptr))); } } From bfb9760d29f280bb4a8e84f96cbad0f10f996f45 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 15:58:34 +0200 Subject: [PATCH 09/21] Fix unicorn read hook --- src/unicorn-emulator/unicorn_x64_emulator.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/unicorn-emulator/unicorn_x64_emulator.cpp b/src/unicorn-emulator/unicorn_x64_emulator.cpp index 1e18be59..c4840092 100644 --- a/src/unicorn-emulator/unicorn_x64_emulator.cpp +++ b/src/unicorn-emulator/unicorn_x64_emulator.cpp @@ -60,6 +60,7 @@ namespace unicorn { case UC_MEM_READ: case UC_MEM_READ_PROT: + case UC_MEM_READ_AFTER: case UC_MEM_READ_UNMAPPED: return memory_operation::read; case UC_MEM_WRITE: @@ -382,7 +383,7 @@ namespace unicorn uce(uc_mem_protect(*this, address, size, static_cast(permissions))); } - emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override + emulator_hook* hook_instruction(const int instruction_type, instruction_hook_callback callback) override { function_wrapper wrapper([c = std::move(callback)](uc_engine*) { return (c() == instruction_hook_continuation::skip_instruction) ? 1 : 0; @@ -524,7 +525,7 @@ namespace unicorn return result; } - emulator_hook* hook_memory_execution(uint64_t address, uint64_t size, + emulator_hook* hook_memory_execution(const uint64_t address, const uint64_t size, memory_execution_hook_callback callback) { auto exec_wrapper = [c = std::move(callback)](uc_engine*, const uint64_t address, @@ -555,14 +556,14 @@ namespace unicorn return this->hook_memory_execution(address, 1, std::move(callback)); } - emulator_hook* hook_memory_read(uint64_t address, size_t size, + emulator_hook* hook_memory_read(const uint64_t address, const size_t size, memory_access_hook_callback callback) override { auto read_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, const uint64_t value) { const auto operation = map_memory_operation(type); - if (operation != memory_permission::none && size > 0) + if (operation == memory_operation::read && size > 0) { c(address, &value, std::min(static_cast(size), sizeof(value))); } @@ -580,16 +581,15 @@ namespace unicorn return container->as_opaque_hook(); } - emulator_hook* hook_memory_write(uint64_t address, size_t size, + emulator_hook* hook_memory_write(const uint64_t address, const size_t size, memory_access_hook_callback callback) override { - auto write_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type, - const uint64_t address, const int size, - const uint64_t value) { + auto write_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type, const uint64_t addr, + const int length, const uint64_t value) { const auto operation = map_memory_operation(type); - if (operation != memory_permission::none && size > 0) + if (operation == memory_operation::write && length > 0) { - c(address, &value, std::min(static_cast(size), sizeof(value))); + c(addr, &value, std::min(static_cast(length), sizeof(value))); } }; From ed711197ae3340390e8a56f10238269922a845a1 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 16:15:56 +0200 Subject: [PATCH 10/21] Fix GDB debugging with icicle --- src/icicle/src/registers.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/icicle/src/registers.rs b/src/icicle/src/registers.rs index 40d00f9c..67c3543e 100644 --- a/src/icicle/src/registers.rs +++ b/src/icicle/src/registers.rs @@ -470,9 +470,9 @@ pub(crate) struct X64RegisterNodes { flags: pcode::VarNode, rflags: pcode::VarNode, fip: pcode::VarNode, - //fcs: pcode::VarNode, + fcs: pcode::VarNode, fdp: pcode::VarNode, - //fds: pcode::VarNode, + fds: pcode::VarNode, fop: pcode::VarNode, } @@ -704,9 +704,9 @@ impl X64RegisterNodes { fip: r("FPUInstructionPointer"), fdp: r("FPUDataPointer"), fop: r("FPULastInstructionOpcode"), - /*fds: r("FDS"), - msr: r("MSR"), - fcs: r("FCS"),*/ + fds: r("DS"), // ? + fcs: r("CS"), // ? + //msr: r("MSR"), fs_base: r("FS_OFFSET"), gs_base: r("GS_OFFSET"), } @@ -939,9 +939,9 @@ impl X64RegisterNodes { X64Register::Flags => self.flags, X64Register::Rflags => self.rflags, X64Register::Fip => self.fip, - //X64Register::Fcs => self.fcs, + X64Register::Fcs => self.fcs, X64Register::Fdp => self.fdp, - //X64Register::Fds => self.fds, + X64Register::Fds => self.fds, X64Register::Fop => self.fop, _ => panic!("Unsupported register"), } From 320af6bb46baa0f378a8569ef75da66ed00c99d1 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 5 Apr 2025 19:28:21 +0200 Subject: [PATCH 11/21] Support GDB stepping ...almost :( --- src/icicle/src/icicle.rs | 46 ++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index 05daf8ae..a72b9d40 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -130,21 +130,25 @@ impl icicle_vm::CodeInjector for InstructionHookInjector { } struct ExecutionHooks { + skip_ip: Option, + stop: Rc>, generic_hooks: HookContainer, specific_hooks: HookContainer, address_mapping: HashMap>, } impl ExecutionHooks { - pub fn new() -> Self { + pub fn new(stop_value: Rc>) -> Self { Self { + skip_ip: None, + stop: stop_value, generic_hooks: HookContainer::new(), specific_hooks: HookContainer::new(), address_mapping: HashMap::new(), } } - pub fn execute(&self, address: u64) { + fn run_hooks(&self, address: u64) { for (_key, func) in self.generic_hooks.get_hooks() { func(address); } @@ -162,6 +166,24 @@ impl ExecutionHooks { } } + pub fn execute(&mut self,cpu: &mut icicle_cpu::Cpu, address: u64) { + let mut skip = false; + if self.skip_ip.is_some() { + skip = self.skip_ip.unwrap() == address; + self.skip_ip = None; + } + + if !skip { + self.run_hooks(address); + } + + if *self.stop.borrow() { + self.skip_ip = Some(address); + cpu.exception.code = ExceptionCode::InstructionLimit as u32; + cpu.exception.value = address; + } + } + pub fn add_generic_hook(&mut self, callback: Box) -> u32 { self.generic_hooks.add_hook(callback) } @@ -190,11 +212,13 @@ impl ExecutionHooks { } pub struct IcicleEmulator { + executing_thread: std::thread::ThreadId, vm: icicle_vm::Vm, reg: registers::X64RegisterNodes, syscall_hooks: HookContainer, violation_hooks: HookContainer bool>, execution_hooks: Rc>, + stop: Rc>, } struct MemoryHook { @@ -245,18 +269,21 @@ impl icicle_cpu::mem::IoMemory for MmioHandler { impl IcicleEmulator { pub fn new() -> Self { let mut virtual_machine = create_x64_vm(); - let exec_hooks = Rc::new(RefCell::new(ExecutionHooks::new())); + let stop_value = Rc::new(RefCell::new(false)); + let exec_hooks = Rc::new(RefCell::new(ExecutionHooks::new(stop_value.clone()))); let exec_hooks_clone = Rc::clone(&exec_hooks); - let hook = icicle_cpu::InstHook::new(move |_: &mut icicle_cpu::Cpu, addr: u64| { - exec_hooks_clone.borrow().execute(addr); + let hook = icicle_cpu::InstHook::new(move |cpu: &mut icicle_cpu::Cpu, addr: u64| { + exec_hooks_clone.borrow_mut().execute(cpu, addr); }); let hook = virtual_machine.cpu.add_hook(hook); virtual_machine.add_injector(InstructionHookInjector { hook }); Self { + stop: stop_value, + executing_thread: std::thread::current().id(), reg: registers::X64RegisterNodes::new(&virtual_machine.cpu.arch), vm: virtual_machine, syscall_hooks: HookContainer::new(), @@ -270,9 +297,12 @@ impl IcicleEmulator { } pub fn start(&mut self, count: u64) { + self.executing_thread = std::thread::current().id(); + *self.stop.borrow_mut() = false; + self.vm.icount_limit = match count { 0 => u64::MAX, - _ => self.vm.cpu.icount + count, + _ => self.vm.cpu.icount.saturating_add(count), }; loop { @@ -331,6 +361,10 @@ impl IcicleEmulator { pub fn stop(&mut self) { self.vm.icount_limit = 0; + + if self.executing_thread == std::thread::current().id() { + *self.stop.borrow_mut() = true; + } } pub fn add_violation_hook(&mut self, callback: Box bool>) -> u32 { From 3450a6a5170cef5d9976929a1e35b735367457ed Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 6 Apr 2025 09:44:46 +0200 Subject: [PATCH 12/21] Fix reading/writing eflags --- src/icicle/src/icicle.rs | 135 +++++++++++++++++++----------------- src/icicle/src/registers.rs | 34 ++++++--- 2 files changed, 95 insertions(+), 74 deletions(-) diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index a72b9d40..3aea4d53 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -519,7 +519,7 @@ impl IcicleEmulator { }; } - pub fn read_register(&mut self, reg: registers::X64Register, buffer: &mut [u8]) -> usize { + fn read_generic_register(&mut self, reg: registers::X64Register, buffer: &mut [u8]) -> usize { let reg_node = self.reg.get_node(reg); let res = self.vm.cpu.read_dynamic(pcode::Value::Var(reg_node)); @@ -531,7 +531,58 @@ impl IcicleEmulator { return reg_node.size.into(); } + + fn read_flags(&mut self, data: &mut [u8]) -> usize + { + const REAL_SIZE: usize = std::mem::size_of::(); + let limit: usize = std::mem::size_of::(); + let size = std::cmp::min(REAL_SIZE, limit); + + let flags: u64 = self.reg.get_flags(&mut self.vm.cpu); + + let copy_size = std::cmp::min(data.len(), size); + data[..copy_size].copy_from_slice(&flags.to_ne_bytes()[..copy_size]); + + return limit; + } + + pub fn read_register(&mut self, reg: registers::X64Register, data: &mut [u8]) -> usize { + match reg { + registers::X64Register::Rflags => self.read_flags::(data), + registers::X64Register::Eflags => self.read_flags::(data), + registers::X64Register::Flags => self.read_flags::(data), + _ => self.read_generic_register(reg, data), + } + } + + fn write_flags(&mut self, data: &[u8]) -> usize + { + const REAL_SIZE: usize = std::mem::size_of::(); + let limit: usize = std::mem::size_of::(); + let size = std::cmp::min(REAL_SIZE, limit); + let copy_size = std::cmp::min(data.len(), size); + + let mut buffer = [0u8; REAL_SIZE]; + self.read_flags::(&mut buffer); + + buffer[..copy_size].copy_from_slice(&data[..copy_size]); + + let flags = u64::from_ne_bytes(buffer); + self.reg.set_flags(&mut self.vm.cpu, flags); + + return limit; + } + pub fn write_register(&mut self, reg: registers::X64Register, data: &[u8]) -> usize { + match reg { + registers::X64Register::Rflags => self.write_flags::(data), + registers::X64Register::Eflags => self.write_flags::(data), + registers::X64Register::Flags => self.write_flags::(data), + _ => self.write_generic_register(reg, data), + } + } + + fn write_generic_register(&mut self, reg: registers::X64Register, data: &[u8]) -> usize { let reg_node = self.reg.get_node(reg); let mut buffer = [0u8; 32]; @@ -541,71 +592,25 @@ impl IcicleEmulator { //let value = icicle_cpu::regs::DynamicValue::new(buffer, reg_node.size.into()); //self.vm.cpu.write_trunc(reg_node, value); + let cpu = &mut self.vm.cpu; + match reg_node.size { - 1 => self - .vm - .cpu - .write_var::<[u8; 1]>(reg_node, buffer[..1].try_into().expect("")), - 2 => self - .vm - .cpu - .write_var::<[u8; 2]>(reg_node, buffer[..2].try_into().expect("")), - 3 => self - .vm - .cpu - .write_var::<[u8; 3]>(reg_node, buffer[..3].try_into().expect("")), - 4 => self - .vm - .cpu - .write_var::<[u8; 4]>(reg_node, buffer[..4].try_into().expect("")), - 5 => self - .vm - .cpu - .write_var::<[u8; 5]>(reg_node, buffer[..5].try_into().expect("")), - 6 => self - .vm - .cpu - .write_var::<[u8; 6]>(reg_node, buffer[..6].try_into().expect("")), - 7 => self - .vm - .cpu - .write_var::<[u8; 7]>(reg_node, buffer[..7].try_into().expect("")), - 8 => self - .vm - .cpu - .write_var::<[u8; 8]>(reg_node, buffer[..8].try_into().expect("")), - 9 => self - .vm - .cpu - .write_var::<[u8; 9]>(reg_node, buffer[..9].try_into().expect("")), - 10 => self - .vm - .cpu - .write_var::<[u8; 10]>(reg_node, buffer[..10].try_into().expect("")), - 11 => self - .vm - .cpu - .write_var::<[u8; 11]>(reg_node, buffer[..11].try_into().expect("")), - 12 => self - .vm - .cpu - .write_var::<[u8; 12]>(reg_node, buffer[..12].try_into().expect("")), - 13 => self - .vm - .cpu - .write_var::<[u8; 13]>(reg_node, buffer[..13].try_into().expect("")), - 14 => self - .vm - .cpu - .write_var::<[u8; 14]>(reg_node, buffer[..14].try_into().expect("")), - 15 => self - .vm - .cpu - .write_var::<[u8; 15]>(reg_node, buffer[..15].try_into().expect("")), - 16 => self - .vm - .cpu - .write_var::<[u8; 16]>(reg_node, buffer[..16].try_into().expect("")), + 1 => cpu.write_var::<[u8; 1]>(reg_node, buffer[..1].try_into().unwrap()), + 2 => cpu.write_var::<[u8; 2]>(reg_node, buffer[..2].try_into().unwrap()), + 3 => cpu.write_var::<[u8; 3]>(reg_node, buffer[..3].try_into().unwrap()), + 4 => cpu.write_var::<[u8; 4]>(reg_node, buffer[..4].try_into().unwrap()), + 5 => cpu.write_var::<[u8; 5]>(reg_node, buffer[..5].try_into().unwrap()), + 6 => cpu.write_var::<[u8; 6]>(reg_node, buffer[..6].try_into().unwrap()), + 7 => cpu.write_var::<[u8; 7]>(reg_node, buffer[..7].try_into().unwrap()), + 8 => cpu.write_var::<[u8; 8]>(reg_node, buffer[..8].try_into().unwrap()), + 9 => cpu.write_var::<[u8; 9]>(reg_node, buffer[..9].try_into().unwrap()), + 10 => cpu.write_var::<[u8; 10]>(reg_node, buffer[..10].try_into().unwrap()), + 11 => cpu.write_var::<[u8; 11]>(reg_node, buffer[..11].try_into().unwrap()), + 12 => cpu.write_var::<[u8; 12]>(reg_node, buffer[..12].try_into().unwrap()), + 13 => cpu.write_var::<[u8; 13]>(reg_node, buffer[..13].try_into().unwrap()), + 14 => cpu.write_var::<[u8; 14]>(reg_node, buffer[..14].try_into().unwrap()), + 15 => cpu.write_var::<[u8; 15]>(reg_node, buffer[..15].try_into().unwrap()), + 16 => cpu.write_var::<[u8; 16]>(reg_node, buffer[..16].try_into().unwrap()), _ => panic!("invalid dynamic value size"), } diff --git a/src/icicle/src/registers.rs b/src/icicle/src/registers.rs index 67c3543e..c32243ec 100644 --- a/src/icicle/src/registers.rs +++ b/src/icicle/src/registers.rs @@ -262,7 +262,6 @@ pub(crate) struct X64RegisterNodes { r14: pcode::VarNode, r15: pcode::VarNode, rip: pcode::VarNode, - eflags: pcode::VarNode, cs: pcode::VarNode, ds: pcode::VarNode, es: pcode::VarNode, @@ -467,18 +466,22 @@ pub(crate) struct X64RegisterNodes { mxcsr: pcode::VarNode, fs_base: pcode::VarNode, gs_base: pcode::VarNode, - flags: pcode::VarNode, - rflags: pcode::VarNode, fip: pcode::VarNode, fcs: pcode::VarNode, fdp: pcode::VarNode, fds: pcode::VarNode, fop: pcode::VarNode, + flags: Vec, } impl X64RegisterNodes { pub fn new(arch: &icicle_cpu::Arch) -> Self { let r = |name: &str| arch.sleigh.get_reg(name).unwrap().var; + let nodes = [ + "CF", "F1", "PF", "F3", "AF", "F5", "ZF", "SF", "TF", "IF", "DF", "OF", "IOPL", "NT", + "F15", "RF", "VM", "AC", "VIF", "VIP", "ID", + ]; + Self { rax: r("RAX"), rbx: r("RBX"), @@ -497,7 +500,6 @@ impl X64RegisterNodes { r14: r("R14"), r15: r("R15"), rip: r("RIP"), - eflags: r("eflags"), cs: r("CS"), ds: r("DS"), es: r("ES"), @@ -699,8 +701,6 @@ impl X64RegisterNodes { fpcw: r("FPUControlWord"), fptag: r("FPUTagWord"), mxcsr: r("MXCSR"), - flags: r("flags"), - rflags: r("rflags"), fip: r("FPUInstructionPointer"), fdp: r("FPUDataPointer"), fop: r("FPULastInstructionOpcode"), @@ -709,6 +709,25 @@ impl X64RegisterNodes { //msr: r("MSR"), fs_base: r("FS_OFFSET"), gs_base: r("GS_OFFSET"), + flags: nodes.map(|name: &str| r(name)).to_vec(), + } + } + + pub fn get_flags(&self, cpu: &mut icicle_cpu::Cpu) -> u64 { + let mut res: u64 = 0; + + for (index, element) in self.flags.iter().enumerate() { + let flag = cpu.read_reg(*element); + res |= (flag & 1) << index; + } + + res + } + + pub fn set_flags(&self, cpu: &mut icicle_cpu::Cpu, value: u64) { + for (index, element) in self.flags.iter().enumerate() { + let flag = (value >> index) & 1; + cpu.write_reg(*element, flag); } } @@ -731,7 +750,6 @@ impl X64RegisterNodes { X64Register::R14 => self.r14, X64Register::R15 => self.r15, X64Register::Rip => self.rip, - X64Register::Eflags => self.eflags, X64Register::Cs => self.cs, X64Register::Ds => self.ds, X64Register::Es => self.es, @@ -936,8 +954,6 @@ impl X64RegisterNodes { X64Register::Mxcsr => self.mxcsr, X64Register::FsBase => self.fs_base, X64Register::GsBase => self.gs_base, - X64Register::Flags => self.flags, - X64Register::Rflags => self.rflags, X64Register::Fip => self.fip, X64Register::Fcs => self.fcs, X64Register::Fdp => self.fdp, From e40e1bfb830e7854ffaf9029280f3ce9b9947ecc Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 6 Apr 2025 10:32:00 +0200 Subject: [PATCH 13/21] Ugly hack to *sometimes* fix instruction skipping --- src/icicle/src/icicle.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index 3aea4d53..3f0d0175 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -130,6 +130,7 @@ impl icicle_vm::CodeInjector for InstructionHookInjector { } struct ExecutionHooks { + vm_ptr: *mut icicle_vm::Vm, skip_ip: Option, stop: Rc>, generic_hooks: HookContainer, @@ -138,8 +139,9 @@ struct ExecutionHooks { } impl ExecutionHooks { - pub fn new(stop_value: Rc>) -> Self { + pub fn new(stop_value: Rc>, vm: &mut icicle_vm::Vm) -> Self { Self { + vm_ptr: vm as *mut icicle_vm::Vm, skip_ip: None, stop: stop_value, generic_hooks: HookContainer::new(), @@ -171,6 +173,13 @@ impl ExecutionHooks { if self.skip_ip.is_some() { skip = self.skip_ip.unwrap() == address; self.skip_ip = None; + + // TODO: Get rid of that + unsafe { + let vm = &mut *self.vm_ptr; + vm.icount_limit = vm.icount_limit.saturating_sub(1); + vm.next_timer = vm.next_timer.saturating_sub(1); + } } if !skip { @@ -213,7 +222,7 @@ impl ExecutionHooks { pub struct IcicleEmulator { executing_thread: std::thread::ThreadId, - vm: icicle_vm::Vm, + vm: Box, reg: registers::X64RegisterNodes, syscall_hooks: HookContainer, violation_hooks: HookContainer bool>, @@ -268,9 +277,9 @@ impl icicle_cpu::mem::IoMemory for MmioHandler { impl IcicleEmulator { pub fn new() -> Self { - let mut virtual_machine = create_x64_vm(); + let mut virtual_machine = Box::new(create_x64_vm()); let stop_value = Rc::new(RefCell::new(false)); - let exec_hooks = Rc::new(RefCell::new(ExecutionHooks::new(stop_value.clone()))); + let exec_hooks = Rc::new(RefCell::new(ExecutionHooks::new(stop_value.clone(), &mut virtual_machine))); let exec_hooks_clone = Rc::clone(&exec_hooks); From cacf2c152c3367b0909bd0163e6fcfd1ac47e6fd Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 6 Apr 2025 17:50:02 +0200 Subject: [PATCH 14/21] Fix single stepping after breakpoints --- src/icicle/src/icicle.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index 3f0d0175..ac0e4c9c 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -130,7 +130,6 @@ impl icicle_vm::CodeInjector for InstructionHookInjector { } struct ExecutionHooks { - vm_ptr: *mut icicle_vm::Vm, skip_ip: Option, stop: Rc>, generic_hooks: HookContainer, @@ -139,9 +138,8 @@ struct ExecutionHooks { } impl ExecutionHooks { - pub fn new(stop_value: Rc>, vm: &mut icicle_vm::Vm) -> Self { + pub fn new(stop_value: Rc>) -> Self { Self { - vm_ptr: vm as *mut icicle_vm::Vm, skip_ip: None, stop: stop_value, generic_hooks: HookContainer::new(), @@ -173,13 +171,6 @@ impl ExecutionHooks { if self.skip_ip.is_some() { skip = self.skip_ip.unwrap() == address; self.skip_ip = None; - - // TODO: Get rid of that - unsafe { - let vm = &mut *self.vm_ptr; - vm.icount_limit = vm.icount_limit.saturating_sub(1); - vm.next_timer = vm.next_timer.saturating_sub(1); - } } if !skip { @@ -222,7 +213,7 @@ impl ExecutionHooks { pub struct IcicleEmulator { executing_thread: std::thread::ThreadId, - vm: Box, + vm: icicle_vm::Vm, reg: registers::X64RegisterNodes, syscall_hooks: HookContainer, violation_hooks: HookContainer bool>, @@ -277,9 +268,9 @@ impl icicle_cpu::mem::IoMemory for MmioHandler { impl IcicleEmulator { pub fn new() -> Self { - let mut virtual_machine = Box::new(create_x64_vm()); + let mut virtual_machine = create_x64_vm(); let stop_value = Rc::new(RefCell::new(false)); - let exec_hooks = Rc::new(RefCell::new(ExecutionHooks::new(stop_value.clone(), &mut virtual_machine))); + let exec_hooks = Rc::new(RefCell::new(ExecutionHooks::new(stop_value.clone()))); let exec_hooks_clone = Rc::clone(&exec_hooks); @@ -307,7 +298,6 @@ impl IcicleEmulator { pub fn start(&mut self, count: u64) { self.executing_thread = std::thread::current().id(); - *self.stop.borrow_mut() = false; self.vm.icount_limit = match count { 0 => u64::MAX, @@ -315,6 +305,12 @@ impl IcicleEmulator { }; loop { + self.vm.cpu.block_id = u64::MAX; + self.vm.cpu.block_offset = 0; + self.vm.cpu.pending_exception = None; + self.vm.cpu.exception.clear(); + *self.stop.borrow_mut() = false; + let reason = self.vm.run(); match reason { From 5fde8c033d93e1f2d977bf78c45b986088385735 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 6 Apr 2025 20:01:18 +0200 Subject: [PATCH 15/21] Fix hooks This fixes #180 --- src/emulator/scoped_hook.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emulator/scoped_hook.hpp b/src/emulator/scoped_hook.hpp index 6246b760..2fd10985 100644 --- a/src/emulator/scoped_hook.hpp +++ b/src/emulator/scoped_hook.hpp @@ -49,7 +49,7 @@ class scoped_hook auto hooks = std::move(this->hooks_); this->hooks_ = {}; - for (auto* hook : hooks_) + for (auto* hook : hooks) { try { From e8ac70f0d041ee3755f00a8c1a3723c7c2259257 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 6 Apr 2025 20:55:51 +0200 Subject: [PATCH 16/21] Use ghidra spec from icicle-python --> https://github.com/icicle-emu/icicle-python --- .../Processors/x86/data/languages/ia.sinc | 798 ++++++++---------- .../x86/data/languages/lockable.sinc | 91 +- .../Processors/x86/data/languages/macros.sinc | 2 +- .../x86/data/languages/x86-32-golang.cspec | 324 +++++++ .../languages/x86-32-golang.register.info | 9 + .../x86/data/languages/x86-64-compat32.pspec | 159 ++++ .../x86/data/languages/x86-64-gcc.cspec | 131 +++ .../x86/data/languages/x86-64-golang.cspec | 428 ++++++++++ .../languages/x86-64-golang.register.info | 10 + .../x86/data/languages/x86-64-win.cspec | 1 + .../x86/data/languages/x86-64.pspec | 1 - .../Processors/x86/data/languages/x86.ldefs | 24 +- .../Processors/x86/data/languages/x86.opinion | 21 +- .../x86/data/languages/x86gcc.cspec | 88 +- .../x86/data/languages/x86win.cspec | 10 +- 15 files changed, 1600 insertions(+), 497 deletions(-) create mode 100644 src/icicle/data/Ghidra/Processors/x86/data/languages/x86-32-golang.cspec create mode 100644 src/icicle/data/Ghidra/Processors/x86/data/languages/x86-32-golang.register.info create mode 100644 src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-compat32.pspec create mode 100644 src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-golang.cspec create mode 100644 src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-golang.register.info diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc b/src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc index 7a200dd1..19edb19c 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc @@ -280,10 +280,10 @@ define context contextreg repprefx=(13,13) # 0xf3 REP prefix xacquireprefx=(12,12) # 0xf2 XACQUIRE prefix xreleaseprefx=(13,13) # 0xf3 XRELEASE prefix - prefix_66=(14,14) # This is not really a OPSIZE override, it means there is an real(read)/implied(vex) 66 byte + prefix_66=(14,14) # This is not really a OPSIZE override, it means there is an real(read)/implied(vex) 66 byte prefix_f3=(13,13) # This is not really a REP override, it means there is an real(read)/implied(vex) f3 byte prefix_f2=(12,12) # This is not really a REPNE override, it means there is a real(read)/implied(vex) f2 byte - mandover=(12,14) # 0x66 0xf2 or 0xf3 overrides (for mandatory prefixes) + mandover=(12,14) # 0x66 0xf2 or 0xf3 overrides (for mandatory prefixes) rexWprefix=(15,15) # REX.W bit prefix (opsize=2 when REX.W is set) rexRprefix=(16,16) # REX.R bit prefix extend r @@ -1145,78 +1145,78 @@ macro ptr8(r,x) { macro push22(x) { mysave:2 = x; - SP = SP -2; - tmp:$(SIZE) = segment(SS,SP); + tmp:$(SIZE) = segment(SS,SP-2); *:2 tmp = mysave; + SP = SP-2; } macro push24(x) { mysave:4 = x; - SP = SP-4; - tmp:$(SIZE) = segment(SS,SP); + tmp:$(SIZE) = segment(SS,SP-4); *:4 tmp = mysave; + SP = SP-4; } macro push28(x) { mysave:8 = x; - SP = SP-8; - tmp:$(SIZE) = segment(SS,SP); + tmp:$(SIZE) = segment(SS,SP-8); *:8 tmp = mysave; + SP = SP-8; } macro push42(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 2; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-2) = mysave; + $(STACKPTR) = $(STACKPTR)-2; } macro push44(x) { mysave:4 = x; - $(STACKPTR) = $(STACKPTR) - 4; - *:4 $(STACKPTR) = mysave; + *:4 ($(STACKPTR)-4) = mysave; + $(STACKPTR) = $(STACKPTR)-4; } macro pushseg44(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 4; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-4) = mysave; + $(STACKPTR) = $(STACKPTR)-4; } macro push48(x) { mysave:8 = x; - $(STACKPTR) = $(STACKPTR) - 8; - *:8 $(STACKPTR) = mysave; + *:8 ($(STACKPTR)-8) = mysave; + $(STACKPTR) = $(STACKPTR)-8; } @ifdef IA64 macro push82(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 2; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-2) = mysave; + $(STACKPTR) = $(STACKPTR)-2; } macro push84(x) { mysave:4 = x; - $(STACKPTR) = $(STACKPTR) - 4; - *:4 $(STACKPTR) = mysave; + *:4 ($(STACKPTR)-4) = mysave; + $(STACKPTR) = $(STACKPTR)-4; } macro push88(x) { mysave:8 = x; - $(STACKPTR) = $(STACKPTR) - 8; - *:8 $(STACKPTR) = mysave; + *:8 ($(STACKPTR)-8) = mysave; + $(STACKPTR) = $(STACKPTR)-8; } macro pushseg82(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 2; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-2) = mysave; + $(STACKPTR) = $(STACKPTR)-2; } macro pushseg88(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 8; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-8) = mysave; + $(STACKPTR) = $(STACKPTR)-8; } @endif @@ -2136,48 +2136,46 @@ with : lockprefx=0 { :CALL rel16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0xe8; rel16 { push22(&:2 inst_next); call rel16; } :CALL rel16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0xe8; rel16 { push42(&:2 inst_next); call rel16; } @ifdef IA64 -:CALL rel16 is $(LONGMODE_ON) & vexMode=0 & (addrsize=1 | addrsize=2) & opsize=0 & byte=0xe8; rel16 { push88(&:8 inst_next); call rel16; } +:CALL rel16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xe8; rel16 { push88(&:8 inst_next); call rel16; } @endif # When is a Call a Jump, when it jumps right after. Not always the case but... :CALL rel16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0xe8; simm16=0 & rel16 { push22(&:2 inst_next); goto rel16; } :CALL rel16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0xe8; simm16=0 & rel16 { push42(&:2 inst_next); goto rel16; } @ifdef IA64 -:CALL rel16 is $(LONGMODE_ON) & vexMode=0 & (addrsize=1 | addrsize=2) & opsize=0 & byte=0xe8; simm16=0 & rel16 { push88(&:8 inst_next); goto rel16; } +:CALL rel16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xe8; simm16=0 & rel16 { push88(&:8 inst_next); goto rel16; } @endif :CALL rel32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0xe8; rel32 { push24(&:4 inst_next); call rel32; } :CALL rel32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xe8; rel32 { push44(&:4 inst_next); call rel32; } @ifdef IA64 -:CALL rel32 is $(LONGMODE_ON) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xe8; rel32 { push88(&:8 inst_next); call rel32; } -:CALL rel32 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & (opsize=1 | opsize=2) & byte=0xe8; rel32 { push88(&:8 inst_next); call rel32; } +:CALL rel32 is $(LONGMODE_ON) & vexMode=0 & (opsize=1 | opsize=2) & byte=0xe8; rel32 { push88(&:8 inst_next); call rel32; } @endif # When is a call a Jump, when it jumps right after. Not always the case but... :CALL rel32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0xe8; simm32=0 & rel32 { push24(&:4 inst_next); goto rel32; } :CALL rel32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xe8; simm32=0 & rel32 { push44(&:4 inst_next); goto rel32; } @ifdef IA64 -:CALL rel32 is $(LONGMODE_ON) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xe8; simm32=0 & rel32 { push88(&:8 inst_next); goto rel32; } -:CALL rel32 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & (opsize=1 | opsize=2) & byte=0xe8; simm32=0 & rel32 { push88(&:8 inst_next); goto rel32; } +:CALL rel32 is $(LONGMODE_ON) & vexMode=0 & (opsize=1 | opsize=2) & byte=0xe8; simm32=0 & rel32 { push88(&:8 inst_next); goto rel32; } @endif :CALL rm16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0xff & currentCS; rm16 & reg_opcode=2 ... { local dest:4 = segment(currentCS,rm16); push22(&:2 inst_next); call [dest]; } :CALL rm16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; rm16 & reg_opcode=2 ... { local dest:2 = rm16; push42(&:2 inst_next); call [dest]; } @ifdef IA64 -:CALL rm16 is $(LONGMODE_ON) & vexMode=0 & (addrsize=1 | addrsize=2) & opsize=0 & byte=0xff; rm16 & reg_opcode=2 ... { local dest:8 = inst_next + zext(rm16); push88(&:8 inst_next); call [dest]; } +:CALL rm16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xff; rm16 & reg_opcode=2 ... { local dest:8 = inst_next + zext(rm16); push88(&:8 inst_next); call [dest]; } @endif :CALL rm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0xff; rm32 & reg_opcode=2 ... { local dest:4 = rm32; push24(&:4 inst_next); call [dest]; } :CALL rm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; rm32 & reg_opcode=2 ... { local dest:4 = rm32; push44(&:4 inst_next); call [dest]; } @ifdef IA64 -:CALL rm64 is $(LONGMODE_ON) & vexMode=0 & (addrsize=1 | addrsize=2) & (opsize=1 | opsize=2) & byte=0xff; rm64 & reg_opcode=2 ... { local dest:8 = rm64; push88(&:8 inst_next); call [dest]; } +:CALL rm64 is $(LONGMODE_ON) & vexMode=0 & (opsize=1 | opsize=2) & byte=0xff; rm64 & reg_opcode=2 ... { local dest:8 = rm64; push88(&:8 inst_next); call [dest]; } @endif # direct far calls generate an opcode undefined exception in x86-64 :CALLF ptr1616 is vexMode=0 & addrsize=0 & opsize=0 & byte=0x9a; ptr1616 { push22(CS); build ptr1616; push22(&:2 inst_next); call ptr1616; } :CALLF ptr1616 is vexMode=0 & addrsize=1 & opsize=0 & byte=0x9a; ptr1616 { push42(CS); build ptr1616; push42(&:2 inst_next); call ptr1616; } :CALLF ptr1632 is vexMode=0 & addrsize=0 & opsize=1 & byte=0x9a; ptr1632 { push22(CS); build ptr1632; push24(&:4 inst_next); call ptr1632; } -:CALLF ptr1632 is vexMode=0 & addrsize=1 & opsize=1 & byte=0x9a; ptr1632 { push42(CS); build ptr1632; push44(&:4 inst_next); call ptr1632; } +:CALLF ptr1632 is vexMode=0 & addrsize=1 & opsize=1 & byte=0x9a; ptr1632 { pushseg44(CS); build ptr1632; push44(&:4 inst_next); call ptr1632; } :CALLF addr16 is vexMode=0 & addrsize=0 & opsize=0 & byte=0xff; addr16 & reg_opcode=3 ... { local ptr:$(SIZE) = segment(DS,addr16); local addrptr:$(SIZE) = segment(*:2 (ptr+2),*:2 ptr); push22(CS); push22(&:2 inst_next); call [addrptr]; } :CALLF addr32 is vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; addr32 & reg_opcode=3 ... { local dest:4 = addr32; push42(CS); push42(&:2 inst_next); call [dest]; } @@ -2187,11 +2185,11 @@ with : lockprefx=0 { :CALLF addr16 is vexMode=0 & addrsize=0 & opsize=1 & byte=0xff; addr16 & reg_opcode=3 ... { local dest:2 = addr16; push22(CS); push24(&:4 inst_next); call [dest]; } -:CALLF addr32 is vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; addr32 & reg_opcode=3 ... { local dest:4 = addr32; push42(CS); push44(&:4 inst_next); call [dest]; } +:CALLF addr32 is vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; addr32 & reg_opcode=3 ... { local dest:4 = addr32; pushseg44(CS); push44(&:4 inst_next); call [dest]; } @ifdef IA64 -:CALLF addr32 is $(LONGMODE_ON) &vexMode=0 & addrsize=1 & opsize=2 & byte=0xff; addr32 & reg_opcode=3 ... { local dest:4 = addr32; push82(CS); push88(&:8 inst_next); call [dest]; } -:CALLF addr64 is $(LONGMODE_ON) &vexMode=0 & addrsize=2 & opsize=1 & byte=0xff; addr64 & reg_opcode=3 ... { local dest:8 = addr64; push82(CS); push84(&:4 inst_next); call [dest]; } -:CALLF addr64 is $(LONGMODE_ON) &vexMode=0 & addrsize=2 & opsize=2 & byte=0xff; addr64 & reg_opcode=3 ... { local dest:8 = addr64; push82(CS); push88(&:8 inst_next); call [dest]; } +:CALLF addr32 is $(LONGMODE_ON) &vexMode=0 & addrsize=1 & opsize=2 & byte=0xff; addr32 & reg_opcode=3 ... { local dest:4 = addr32; pushseg88(CS); push88(&:8 inst_next); call [dest]; } +:CALLF addr64 is $(LONGMODE_ON) &vexMode=0 & addrsize=2 & opsize=1 & byte=0xff; addr64 & reg_opcode=3 ... { local dest:8 = addr64; pushseg44(CS); push84(&:4 inst_next); call [dest]; } +:CALLF addr64 is $(LONGMODE_ON) &vexMode=0 & addrsize=2 & opsize=2 & byte=0xff; addr64 & reg_opcode=3 ... { local dest:8 = addr64; pushseg88(CS); push88(&:8 inst_next); call [dest]; } @endif :CBW is vexMode=0 & opsize=0 & byte=0x98 { AX = sext(AL); } @@ -2246,56 +2244,75 @@ define pcodeop clzero; @ifdef IA64 :CMP RAX,simm32 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x3d; RAX & simm32 { subflags( RAX,simm32); local tmp = RAX - simm32; resultflags(tmp); } @endif -:CMP spec_rm8,imm8 is vexMode=0 & $(BYTE_80_82); spec_rm8 & reg_opcode=7 ...; imm8 { subflags( spec_rm8,imm8 ); local tmp = spec_rm8 - imm8; resultflags(tmp); } -:CMP spec_rm16,imm16 is vexMode=0 & opsize=0 & byte=0x81; spec_rm16 & reg_opcode=7 ...; imm16 { subflags( spec_rm16,imm16); local tmp = spec_rm16 - imm16; resultflags(tmp); } -:CMP spec_rm32,imm32 is vexMode=0 & opsize=1 & byte=0x81; spec_rm32 & reg_opcode=7 ...; imm32 { subflags( spec_rm32,imm32); local tmp = spec_rm32 - imm32; resultflags(tmp); } +:CMP spec_rm8,imm8 is vexMode=0 & $(BYTE_80_82); spec_rm8 & reg_opcode=7 ...; imm8 { local temp:1 = spec_rm8; subflags(temp,imm8 ); local diff = temp - imm8; resultflags(diff); } +:CMP spec_rm16,imm16 is vexMode=0 & opsize=0 & byte=0x81; spec_rm16 & reg_opcode=7 ...; imm16 { local temp:2 = spec_rm16; subflags(temp,imm16); local diff = temp - imm16; resultflags(diff); } +:CMP spec_rm32,imm32 is vexMode=0 & opsize=1 & byte=0x81; spec_rm32 & reg_opcode=7 ...; imm32 { local temp:4 = spec_rm32; subflags(temp,imm32); local diff = temp - imm32; resultflags(diff); } @ifdef IA64 -:CMP spec_rm64,simm32 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x81; spec_rm64 & reg_opcode=7 ...; simm32 { subflags( spec_rm64,simm32); local tmp = spec_rm64 - simm32; resultflags(tmp); } +:CMP spec_rm64,simm32 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x81; spec_rm64 & reg_opcode=7 ...; simm32 { local temp:8 = spec_rm64; subflags(temp,simm32); local diff = temp - simm32; resultflags(diff); } @endif -:CMP spec_rm16,simm8_16 is vexMode=0 & opsize=0 & byte=0x83; spec_rm16 & reg_opcode=7 ...; simm8_16 { subflags( spec_rm16,simm8_16); local tmp = spec_rm16 - simm8_16; resultflags(tmp); } -:CMP spec_rm32,simm8_32 is vexMode=0 & opsize=1 & byte=0x83; spec_rm32 & reg_opcode=7 ...; simm8_32 { subflags( spec_rm32,simm8_32); local tmp = spec_rm32 - simm8_32; resultflags(tmp); } +:CMP spec_rm16,simm8_16 is vexMode=0 & opsize=0 & byte=0x83; spec_rm16 & reg_opcode=7 ...; simm8_16 { local temp:2 = spec_rm16; subflags(temp,simm8_16); local diff = temp - simm8_16; resultflags(diff); } +:CMP spec_rm32,simm8_32 is vexMode=0 & opsize=1 & byte=0x83; spec_rm32 & reg_opcode=7 ...; simm8_32 { local temp:4 = spec_rm32; subflags(temp,simm8_32); local diff = temp - simm8_32; resultflags(diff); } @ifdef IA64 -:CMP spec_rm64,simm8_64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x83; spec_rm64 & reg_opcode=7 ...; simm8_64 { subflags( spec_rm64,simm8_64); local tmp = spec_rm64 - simm8_64; resultflags(tmp); } +:CMP spec_rm64,simm8_64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x83; spec_rm64 & reg_opcode=7 ...; simm8_64 { local temp:8 = spec_rm64; subflags(temp,simm8_64); local diff = temp - simm8_64; resultflags(diff); } @endif -:CMP rm8,Reg8 is vexMode=0 & byte=0x38; rm8 & Reg8 ... { subflags( rm8,Reg8 ); local tmp = rm8 - Reg8; resultflags(tmp); } -:CMP rm16,Reg16 is vexMode=0 & opsize=0 & byte=0x39; rm16 & Reg16 ... { subflags( rm16,Reg16); local tmp = rm16 - Reg16; resultflags(tmp); } -:CMP rm32,Reg32 is vexMode=0 & opsize=1 & byte=0x39; rm32 & Reg32 ... { subflags( rm32, Reg32 ); local tmp = rm32 - Reg32; resultflags(tmp); } +:CMP rm8,Reg8 is vexMode=0 & byte=0x38; rm8 & Reg8 ... { local temp:1 = rm8; subflags(temp,Reg8); local diff = temp - Reg8; resultflags(diff); } +:CMP rm16,Reg16 is vexMode=0 & opsize=0 & byte=0x39; rm16 & Reg16 ... { local temp:2 = rm16; subflags(temp,Reg16); local diff = temp - Reg16; resultflags(diff); } +:CMP rm32,Reg32 is vexMode=0 & opsize=1 & byte=0x39; rm32 & Reg32 ... { local temp:4 = rm32; subflags(temp,Reg32 ); local diff = temp - Reg32; resultflags(diff); } @ifdef IA64 -:CMP rm64,Reg64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x39; rm64 & Reg64 ... { subflags( rm64,Reg64); local tmp = rm64 - Reg64; resultflags(tmp); } +:CMP rm64,Reg64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x39; rm64 & Reg64 ... { local temp:8 = rm64; subflags(temp,Reg64); local diff = temp - Reg64; resultflags(diff); } @endif -:CMP Reg8,rm8 is vexMode=0 & byte=0x3a; rm8 & Reg8 ... { subflags( Reg8,rm8 ); local tmp = Reg8 - rm8; resultflags(tmp); } -:CMP Reg16,rm16 is vexMode=0 & opsize=0 & byte=0x3b; rm16 & Reg16 ... { subflags(Reg16,rm16 ); local tmp = Reg16 - rm16; resultflags(tmp); } -:CMP Reg32,Rmr32 is vexMode=0 & opsize=1 & byte=0x3b; Reg32 & mod=3 & Rmr32 { subflags(Reg32,Rmr32 ); local tmp = Reg32 - Rmr32; resultflags(tmp); } -:CMP Reg32,m32 is vexMode=0 & opsize=1 & byte=0x3b; Reg32 ... & m32 {subflags(Reg32,m32 ); local tmp = Reg32 - m32; resultflags(tmp); } +:CMP Reg8,rm8 is vexMode=0 & byte=0x3a; rm8 & Reg8 ... { local temp:1 = rm8; subflags(Reg8,temp); local diff = Reg8 - temp; resultflags(diff); } +:CMP Reg16,rm16 is vexMode=0 & opsize=0 & byte=0x3b; rm16 & Reg16 ... { local temp:2 = rm16; subflags(Reg16,temp); local diff = Reg16 - temp; resultflags(diff); } +:CMP Reg32,Rmr32 is vexMode=0 & opsize=1 & byte=0x3b; Reg32 & mod=3 & Rmr32 { local temp:4 = Rmr32; subflags(Reg32,temp); local diff = Reg32 - temp; resultflags(diff); } +:CMP Reg32,m32 is vexMode=0 & opsize=1 & byte=0x3b; Reg32 ... & m32 {local temp:4 = m32; subflags(Reg32, temp); local diff = Reg32 - temp; resultflags(diff); } @ifdef IA64 -:CMP Reg64,rm64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x3b; rm64 & Reg64 ... { subflags(Reg64,rm64 ); local tmp = Reg64 - rm64; resultflags(tmp); } +:CMP Reg64,rm64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x3b; rm64 & Reg64 ... { local temp:8 = rm64; subflags(Reg64,temp); local diff = Reg64 - temp; resultflags(diff); } @endif -:CMPSB^repe^repetail eseDI1,dseSI1 is vexMode=0 & repe & repetail & byte=0xa6 & dseSI1 & eseDI1 { build repe; build eseDI1; build dseSI1; subflags(dseSI1,eseDI1); local diff=dseSI1-eseDI1; resultflags(diff); build repetail; } -:CMPSW^repe^repetail eseDI2,dseSI2 is vexMode=0 & repe & repetail & opsize=0 & byte=0xa7 & dseSI2 & eseDI2 { build repe; build eseDI2; build dseSI2; subflags(dseSI2,eseDI2); local diff=dseSI2-eseDI2; resultflags(diff); build repetail; } -:CMPSD^repe^repetail eseDI4,dseSI4 is vexMode=0 & repe & repetail & opsize=1 & byte=0xa7 & dseSI4 & eseDI4 { build repe; build eseDI4; build dseSI4; subflags(dseSI4,eseDI4); local diff=dseSI4-eseDI4; resultflags(diff); build repetail; } +:CMPSB^repe^repetail eseDI1,dseSI1 is vexMode=0 & repe & repetail & byte=0xa6 & dseSI1 & eseDI1 { build repe; build eseDI1; build dseSI1; local temp_DI1:1 = eseDI1; local temp_SI1:1 = dseSI1; subflags(temp_SI1,temp_DI1); local diff=temp_SI1 - temp_DI1; resultflags(diff); build repetail; } +:CMPSW^repe^repetail eseDI2,dseSI2 is vexMode=0 & repe & repetail & opsize=0 & byte=0xa7 & dseSI2 & eseDI2 { build repe; build eseDI2; build dseSI2; local temp_DI2:2 = eseDI2; local temp_SI2:2 = dseSI2; subflags(temp_SI2,temp_DI2); local diff=temp_SI2 - temp_DI2; resultflags(diff); build repetail; } +:CMPSD^repe^repetail eseDI4,dseSI4 is vexMode=0 & repe & repetail & opsize=1 & byte=0xa7 & dseSI4 & eseDI4 { build repe; build eseDI4; build dseSI4; local temp_DI4:4 = eseDI4; local temp_SI4:4 = dseSI4; subflags(temp_SI4,temp_DI4); local diff=temp_SI4 - temp_DI4; resultflags(diff); build repetail; } @ifdef IA64 -:CMPSD^repe^repetail eseDI8,dseSI8 is $(LONGMODE_ON) & vexMode=0 & repe & repetail & opsize=2 & byte=0xa7 & dseSI8 & eseDI8 { build repe; build eseDI8; build dseSI8; subflags(dseSI8,eseDI8); local diff=dseSI8-eseDI8; resultflags(diff); build repetail; } +:CMPSD^repe^repetail eseDI8,dseSI8 is $(LONGMODE_ON) & vexMode=0 & repe & repetail & opsize=2 & byte=0xa7 & dseSI8 & eseDI8 { build repe; build eseDI8; build dseSI8; local temp_DI8:8 = eseDI8; local temp_SI8:8 = dseSI8; subflags(temp_SI8,temp_DI8); local diff=temp_SI8-temp_DI8; resultflags(diff); build repetail; } @endif # See 'lockable.sinc' for memory destination, lockable variants -:CMPXCHG Rmr8,Reg8 is vexMode=0 & byte=0xf; byte=0xb0; mod=3 & Rmr8 & Reg8 { subflags(AL,Rmr8); local tmp=AL-Rmr8; resultflags(tmp); - local diff = Rmr8^Reg8; Rmr8 = Rmr8 ^ (ZF*diff); - diff = AL ^ Rmr8; AL = AL ^ ((ZF==0)*diff); } -:CMPXCHG Rmr16,Reg16 is vexMode=0 & opsize=0 & byte=0xf; byte=0xb1; mod=3 & Rmr16 & Reg16 { subflags(AX,Rmr16); local tmp=AX-Rmr16; resultflags(tmp); - local diff = Rmr16^Reg16; Rmr16 = Rmr16 ^ (zext(ZF) * diff); - diff = AX ^ Rmr16; AX = AX ^ (zext(ZF==0) * diff); } +:CMPXCHG Rmr8,Reg8 is vexMode=0 & byte=0xf; byte=0xb0; mod=3 & Rmr8 & Reg8 +{ + local dest = Rmr8; + subflags(AL,dest); + local diff = AL-dest; + resultflags(diff); + if (ZF) goto ; + AL = dest; + goto inst_next; + + Rmr8 = Reg8; + } +:CMPXCHG Rmr16,Reg16 is vexMode=0 & opsize=0 & byte=0xf; byte=0xb1; mod=3 & Rmr16 & Reg16 +{ + local dest = Rmr16; + subflags(AX,dest); + local diff = AX-dest; + resultflags(diff); + if (ZF) goto ; + AX = dest; + goto inst_next; + + Rmr16 = Reg16; + } :CMPXCHG Rmr32,Reg32 is vexMode=0 & opsize=1 & byte=0xf; byte=0xb1; mod=3 & Rmr32 & Reg32 & check_EAX_dest & check_Rmr32_dest { #this instruction writes to either EAX or Rmr32 #in 64-bit mode, a 32-bit register that is written to #(and only the register that is written to) #must be zero-extended to 64 bits - subflags(EAX,Rmr32); - local tmp=EAX-Rmr32; - resultflags(tmp); - if (ZF==1) goto ; - EAX = Rmr32; + local dest = Rmr32; + subflags(EAX,dest); + local diff = EAX-dest; + resultflags(diff); + if (ZF) goto ; + EAX = dest; build check_EAX_dest; goto inst_next; @@ -2303,9 +2320,18 @@ define pcodeop clzero; build check_Rmr32_dest; } @ifdef IA64 -:CMPXCHG Rmr64,Reg64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0xf; byte=0xb1; mod=3 & Rmr64 & Reg64 { subflags(RAX,Rmr64); local tmp=RAX-Rmr64; resultflags(tmp); - local diff = Rmr64^Reg64; Rmr64 = Rmr64 ^ (zext(ZF) * diff); - diff = RAX ^ Rmr64; RAX = RAX ^ (zext(ZF==0) * diff); } +:CMPXCHG Rmr64,Reg64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0xf; byte=0xb1; mod=3 & Rmr64 & Reg64 +{ + local dest = Rmr64; + subflags(RAX,dest); + local diff = RAX-dest; + resultflags(diff); + if (ZF) goto ; + RAX = dest; + goto inst_next; + + Rmr64 = Reg64; +} @endif # CMPXCHG8B See 'lockable.sinc' for memory destination, lockable variants @@ -2480,99 +2506,13 @@ define pcodeop cpuid_brand_part3_info; enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } -@ifdef IA64 -:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0xc8; imm16; enterFrames & low5=0x00 { - push88(RBP); - RBP = RSP; - RSP = RSP - imm16; -} - -:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0xc8; imm16; enterFrames & low5=0x01 { - push88(RBP); - frameTemp:8 = RSP; - - push88(frameTemp); - RBP = frameTemp; - RSP = RSP - imm16; -} - -:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=2 & byte=0xc8; imm16; enterFrames { - push88(RBP); - frameTemp:8 = RSP; - - RSPt:$(SIZE) = RSP; - RBPt:$(SIZE) = RBP; - ii:1 = enterFrames - 1; - - RBPt = RBPt - 8; - RSPt = RSPt - 8; - *:8 RSPt = *:8 RBPt; - ii = ii - 1; - if (ii s> 0) goto ; - - tmp_offset:8 = 8 * zext(enterFrames - 1); - RSP = RSP - tmp_offset; - RBP = RBP - tmp_offset; - - push88(frameTemp); - RBP = frameTemp; - RSP = RSP - imm16; -} - -:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=1 & byte=0xc8; imm16; enterFrames { - push88(RBP); - frameTemp:8 = RSP; - - RSPt:$(SIZE) = RSP; - RBPt:$(SIZE) = RBP; - ii:1 = enterFrames - 1; - - RBPt = RBPt - 4; - RSPt = RSPt - 4; - *:4 RSPt = *:4 RBPt; - ii = ii - 1; - if (ii s> 0) goto ; - - tmp_offset:8 = 4 * zext(enterFrames - 1); - RSP = RSP - tmp_offset; - RBP = RBP - tmp_offset; - - push88(frameTemp); - RBP = frameTemp; - RSP = RSP - imm16; -} - -:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & byte=0xc8; imm16; enterFrames { - push88(RBP); - frameTemp:8 = RSP; - - RSPt:$(SIZE) = RSP; - RBPt:$(SIZE) = RBP; - ii:1 = enterFrames - 1; - - RBPt = RBPt - 2; - RSPt = RSPt - 2; - *:2 RSPt = *:2 RBPt; - ii = ii - 1; - if (ii s> 0) goto ; - - tmp_offset:8 = 2 * zext(enterFrames - 1); - RSP = RSP - tmp_offset; - RBP = RBP - tmp_offset; - - push88(frameTemp); - RBP = frameTemp; - RSP = RSP - imm16; -} -@endif - -:ENTER imm16,enterFrames is vexMode=0 & addrsize=1 & byte=0xc8; imm16; enterFrames & low5=0x00 { +:ENTER imm16,enterFrames is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0xc8; imm16; enterFrames & low5=0x00 { push44(EBP); EBP = ESP; ESP = ESP - imm16; } -:ENTER imm16,enterFrames is vexMode=0 & addrsize=1 & byte=0xc8; imm16; enterFrames & low5=0x01 { +:ENTER imm16,enterFrames is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0xc8; imm16; enterFrames & low5=0x01 { push44(EBP); frameTemp:4 = ESP; @@ -2581,10 +2521,9 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } ESP = ESP - imm16; } -:ENTER imm16,enterFrames is vexMode=0 & addrsize=1 & opsize=1 & byte=0xc8; imm16; enterFrames { +:ENTER imm16,enterFrames is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xc8; imm16; enterFrames { push44(EBP); frameTemp:4 = ESP; - @ifdef IA64 ESPt:$(SIZE) = zext(ESP); EBPt:$(SIZE) = zext(EBP); @@ -2592,6 +2531,7 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } ESPt:$(SIZE) = ESP; EBPt:$(SIZE) = EBP; @endif + ii:1 = enterFrames - 1; EBPt = EBPt - 4; @@ -2609,10 +2549,9 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } ESP = ESP - imm16; } -:ENTER imm16,enterFrames is vexMode=0 & addrsize=1 & opsize=0 & byte=0xc8; imm16; enterFrames { +:ENTER imm16,enterFrames is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0xc8; imm16; enterFrames { push44(EBP); frameTemp:4 = ESP; - @ifdef IA64 ESPt:$(SIZE) = zext(ESP); EBPt:$(SIZE) = zext(EBP); @@ -2620,6 +2559,7 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } ESPt:$(SIZE) = ESP; EBPt:$(SIZE) = EBP; @endif + ii:1 = enterFrames - 1; EBPt = EBPt - 2; @@ -2637,13 +2577,13 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } ESP = ESP - imm16; } -:ENTER imm16,enterFrames is vexMode=0 & addrsize=0 & byte=0xc8; imm16; enterFrames & low5=0x00 { +:ENTER imm16,enterFrames is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0xc8; imm16; enterFrames & low5=0x00 { push22(BP); BP = SP; SP = SP - imm16; } -:ENTER imm16,enterFrames is vexMode=0 & addrsize=0 & byte=0xc8; imm16; enterFrames & low5=0x01 { +:ENTER imm16,enterFrames is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0xc8; imm16; enterFrames & low5=0x01 { push22(BP); frameTemp:2 = SP; @@ -2652,7 +2592,7 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } SP = SP - imm16; } -:ENTER imm16,enterFrames is vexMode=0 & seg16 & addrsize=0 & opsize=1 & byte=0xc8; imm16; enterFrames { +:ENTER imm16,enterFrames is $(LONGMODE_OFF) & vexMode=0 & seg16 & addrsize=0 & opsize=1 & byte=0xc8; imm16; enterFrames { push24(zext(BP)); frameTemp:2 = SP; @@ -2678,7 +2618,7 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } SP = SP - imm16; } -:ENTER imm16,enterFrames is vexMode=0 & seg16 & addrsize=0 & opsize=0 & byte=0xc8; imm16; enterFrames { +:ENTER imm16,enterFrames is $(LONGMODE_OFF) & vexMode=0 & seg16 & addrsize=0 & opsize=0 & byte=0xc8; imm16; enterFrames { push22(BP); frameTemp:2 = SP; @@ -2703,6 +2643,86 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } SP = SP - imm16; } +@ifdef IA64 +:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & byte=0xc8; imm16; enterFrames & low5=0x00 { + push88(RBP); + RBP = RSP; + RSP = RSP - imm16; +} + +:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & byte=0xc8; imm16; enterFrames & low5=0x01 { + push88(RBP); + frameTemp:8 = RSP; + + push88(frameTemp); + RBP = frameTemp; + RSP = RSP - imm16; +} + +:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & byte=0xc8; imm16; enterFrames { + push88(RBP); + frameTemp:8 = RSP; + + RSPt:$(SIZE) = RSP; + RBPt:$(SIZE) = RBP; + ii:1 = enterFrames - 1; + + RBPt = RBPt - 8; + RSPt = RSPt - 8; + *:8 RSPt = *:8 RBPt; + ii = ii - 1; + if (ii s> 0) goto ; + + tmp_offset:8 = 8 * zext(enterFrames - 1); + RSP = RSP - tmp_offset; + RBP = RBP - tmp_offset; + + push88(frameTemp); + RBP = frameTemp; + RSP = RSP - imm16; +} + +:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xc8; imm16; enterFrames & low5=0x00 { + push82(BP); + RBP = RSP; + RSP = RSP - imm16; +} + +:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xc8; imm16; enterFrames & low5=0x01 { + push82(BP); + frameTemp:2 = SP; + + push82(frameTemp); + BP = frameTemp; + RSP = RSP - imm16; +} + +:ENTER imm16,enterFrames is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xc8; imm16; enterFrames { + push82(BP); + frameTemp:2 = SP; + + RSPt:$(SIZE) = RSP; + RBPt:$(SIZE) = RBP; + ii:1 = enterFrames - 1; + + RBPt = RBPt - 2; + RSPt = RSPt - 2; + *:2 RSPt = *:2 RBPt; + ii = ii - 1; + if (ii s> 0) goto ; + + tmp_offset:8 = 2 * zext(enterFrames - 1); + RSP = RSP - tmp_offset; + RBP = RBP - tmp_offset; + + push82(frameTemp); + BP = frameTemp; + RSP = RSP - imm16; +} +@endif + + + # Informs the 80287 coprocessor of the switch to protected mode, treated as NOP for 80387 and later. # We used to have a pseudo-op, but as this is a legacy instruction which is now explicitly treated # as a NOP. We treat it as a NOP as well. @@ -2849,30 +2869,32 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } :IRETQ is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=2 & byte=0xcf { pop88(RIP); tmp:8=0; pop88(tmp); CS=tmp(0); pop88(rflags); return [RIP]; } @endif -:J^cc rel8 is vexMode=0 & row=7 & cc; rel8 { if (cc) goto rel8; } -:J^cc rel16 is vexMode=0 & bit64=0 & opsize=0 & byte=0xf; row=8 & cc; rel16 { if (cc) goto rel16; } -:J^cc rel32 is vexMode=0 & opsize=1 & byte=0xf; row=8 & cc; rel32 { if (cc) goto rel32; } -:J^cc rel32 is vexMode=0 & opsize=2 & byte=0xf; row=8 & cc; rel32 { if (cc) goto rel32; } +:J^cc rel8 is vexMode=0 & row=7 & cc; rel8 { if (cc) goto rel8; } +:J^cc rel16 is $(LONGMODE_OFF) & vexMode=0 & opsize=0 & byte=0xf; row=8 & cc; rel16 { if (cc) goto rel16; } +:J^cc rel32 is vexMode=0 & opsize=1 & byte=0xf; row=8 & cc; rel32 { if (cc) goto rel32; } +:J^cc rel32 is vexMode=0 & opsize=2 & byte=0xf; row=8 & cc; rel32 { if (cc) goto rel32; } # The following is vexMode=0 & picked up by the line above. rel32 works for both 32 and 64 bit #@ifdef IA64 #:J^cc rel32 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0xf; row=8 & cc; rel32 { if (cc) goto rel32; } #@endif -:JCXZ rel8 is vexMode=0 & opsize=0 & byte=0xe3; rel8 { if (CX==0) goto rel8; } -:JECXZ rel8 is vexMode=0 & opsize=1 & byte=0xe3; rel8 { if (ECX==0) goto rel8; } +:JCXZ rel8 is vexMode=0 & addrsize=0 & byte=0xe3; rel8 { if (CX==0) goto rel8; } +:JECXZ rel8 is vexMode=0 & addrsize=1 & byte=0xe3; rel8 { if (ECX==0) goto rel8; } @ifdef IA64 -:JRCXZ rel8 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0xe3; rel8 { if (RCX==0) goto rel8; } +:JRCXZ rel8 is $(LONGMODE_ON) & addrsize=2 & vexMode=0 & byte=0xe3; rel8 { if (RCX==0) goto rel8; } @endif :JMP rel8 is vexMode=0 & byte=0xeb; rel8 { goto rel8; } :JMP rel16 is vexMode=0 & opsize=0 & byte=0xe9; rel16 { goto rel16; } :JMP rel32 is vexMode=0 & opsize=1 & byte=0xe9; rel32 { goto rel32; } :JMP rel32 is vexMode=0 & opsize=2 & byte=0xe9; rel32 { goto rel32; } -:JMP rm16 is vexMode=0 & addrsize=0 & opsize=0 & byte=0xff & currentCS; rm16 & reg_opcode=4 ... { target:4 = segment(currentCS,rm16); goto [target]; } -:JMP rm16 is vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; rm16 & reg_opcode=4 ... { goto [rm16]; } -:JMP rm32 is vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; rm32 & reg_opcode=4 ... { goto [rm32]; } + +:JMP rm16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0xff & currentCS; rm16 & reg_opcode=4 ... { target:4 = segment(currentCS,rm16); goto [target]; } +:JMP rm16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; rm16 & reg_opcode=4 ... { goto [rm16]; } +:JMP rm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; rm32 & reg_opcode=4 ... { goto [rm32]; } @ifdef IA64 -:JMP rm64 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0xff; rm64 & reg_opcode=4 ... { goto [rm64]; } +:JMP rm16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xff & currentCS; rm16 & reg_opcode=4 ... { goto [rm16]; } +:JMP rm64 is $(LONGMODE_ON) & vexMode=0 & byte=0xff; rm64 & reg_opcode=4 ... { goto [rm64]; } @endif :JMPF ptr1616 is $(LONGMODE_OFF) & vexMode=0 & opsize=0 & byte=0xea; ptr1616 { goto ptr1616; } @@ -2946,42 +2968,44 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } :LEA Reg64,addr64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & addrsize=2 & byte=0x8D; addr64 & Reg64 ... { Reg64 = addr64; } @endif -:LEAVE is vexMode=0 & addrsize=0 & byte=0xc9 { SP = BP; tmp:$(SIZE) = segment(SS,SP); BP = *tmp; SP = SP + 2; } -:LEAVE is vexMode=0 & addrsize=1 & byte=0xc9 { ESP = EBP; EBP = *$(STACKPTR); ESP=ESP+4; } +:LEAVE is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0xc9 { SP = BP; pop22(BP); } +:LEAVE is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0xc9 { ESP = EBP; pop24(EBP); } +:LEAVE is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xc9 { ESP = EBP; pop44(EBP); } +:LEAVE is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0xc9 { ESP = EBP; pop42(EBP); } @ifdef IA64 -:LEAVE is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0xc9 { RSP = RBP; RBP = *RSP; RSP=RSP+8; } +:LEAVE is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xc9 { RSP = RBP; pop82(BP); } +:LEAVE is $(LONGMODE_ON) & vexMode=0 & byte=0xc9 { RSP = RBP; pop88(RBP); } @endif define pcodeop GlobalDescriptorTableRegister; -:LGDT m16 is vexMode=0 & opsize=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=2 ) ... & m16 +:LGDT m16 is $(LONGMODE_OFF) & vexMode=0 & opsize=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=2 ) ... & m16 { GlobalDescriptorTableRegister(m16); } -:LGDT m32 is vexMode=0 & opsize=1 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=2 ) ... & m32 +:LGDT m32 is $(LONGMODE_OFF) & vexMode=0 & opsize=1 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=2 ) ... & m32 { GlobalDescriptorTableRegister(m32); } - @ifdef IA64 -:LGDT m64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=2 ) ... & m64 +:LGDT m64 is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=2 ) ... & m64 { GlobalDescriptorTableRegister(m64); } @endif define pcodeop InterruptDescriptorTableRegister; -:LIDT m16 is vexMode=0 & opsize=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=3 ) ... & m16 +:LIDT m16 is $(LONGMODE_OFF) & vexMode=0 & opsize=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=3 ) ... & m16 { InterruptDescriptorTableRegister(m16); } -:LIDT m32 is vexMode=0 & opsize=1 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=3 ) ... & m32 +:LIDT m32 is $(LONGMODE_OFF) & vexMode=0 & opsize=1 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=3 ) ... & m32 { InterruptDescriptorTableRegister(m32); } @ifdef IA64 -:LIDT m64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=3 ) ... & m64 +:LIDT m64 is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=3 ) ... & m64 { InterruptDescriptorTableRegister(m64); } @@ -3165,35 +3189,35 @@ define pcodeop TaskRegister; @endif } @ifdef IA64 -:MOV creg_x, Rmr32 is vexMode=0 & rexRprefix=1 & byte=0xf; byte=0x22; Rmr32 & creg_x { creg_x=zext(Rmr32); } -:MOV creg, Rmr64 is $(LONGMODE_ON) & vexMode=0 & bit64=1 & byte=0xf; byte=0x22; Rmr64 & creg { creg=Rmr64; } -:MOV creg_x, Rmr64 is $(LONGMODE_ON) & vexMode=0 & bit64=1 & rexRprefix=1 & byte=0xf; byte=0x22; Rmr64 & creg_x { creg_x=Rmr64; } +:MOV creg, Rmr64 is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0x22; Rmr64 & creg { creg=Rmr64; } +:MOV creg_x, Rmr64 is $(LONGMODE_ON) & vexMode=0 & rexRprefix=1 & byte=0xf; byte=0x22; Rmr64 & creg_x { creg_x=Rmr64; } @endif -:MOV Rmr32, creg is vexMode=0 & byte=0xf; byte=0x20; Rmr32 & creg { + +:MOV Rmr32, creg is $(LONGMODE_OFF) & vexMode=0 & byte=0xf; byte=0x20; Rmr32 & creg { @ifdef IA64 Rmr32 = creg:4; @else Rmr32 = creg; @endif } -:MOV Rmr32, creg_x is vexMode=0 & rexRprefix=1 & byte=0xf; byte=0x20; Rmr32 & creg_x { Rmr32 = creg_x:4; } @ifdef IA64 -:MOV Rmr64, creg is $(LONGMODE_ON) & vexMode=0 & bit64=1 & byte=0xf; byte=0x20; Rmr64 & creg { Rmr64 = creg; } -:MOV Rmr64, creg_x is $(LONGMODE_ON) & vexMode=0 & bit64=1 & rexRprefix=1 & byte=0xf; byte=0x20; Rmr64 & creg_x { Rmr64 = creg_x; } +:MOV Rmr64, creg is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0x20; Rmr64 & creg { Rmr64 = creg; } +:MOV Rmr64, creg_x is $(LONGMODE_ON) & vexMode=0 & rexRprefix=1 & byte=0xf; byte=0x20; Rmr64 & creg_x { Rmr64 = creg_x; } @endif -:MOV Rmr32, debugreg is vexMode=0 & byte=0xf; byte=0x21; Rmr32 & debugreg { + +:MOV Rmr32, debugreg is $(LONGMODE_OFF) & vexMode=0 & byte=0xf; byte=0x21; Rmr32 & debugreg { @ifdef IA64 Rmr32 = debugreg:4; @else Rmr32 = debugreg; @endif } -:MOV Rmr32, debugreg_x is vexMode=0 & rexRprefix=1 & byte=0xf; byte=0x21; Rmr32 & debugreg_x { Rmr32 = debugreg_x:4; } @ifdef IA64 :MOV Rmr64, debugreg is $(LONGMODE_ON) & vexMode=0 & bit64=1 & byte=0xf; byte=0x21; Rmr64 & debugreg { Rmr64 = debugreg; } :MOV Rmr64, debugreg_x is $(LONGMODE_ON) & vexMode=0 & bit64=1 & rexRprefix=1 & byte=0xf; byte=0x21; Rmr64 & debugreg_x { Rmr64 = debugreg_x; } @endif -:MOV debugreg, Rmr32 is vexMode=0 & byte=0xf; byte=0x23; Rmr32 & debugreg { + +:MOV debugreg, Rmr32 is $(LONGMODE_OFF) & vexMode=0 & byte=0xf; byte=0x23; Rmr32 & debugreg { @ifdef IA64 debugreg = zext(Rmr32); @else @@ -3201,7 +3225,6 @@ define pcodeop TaskRegister; @endif } @ifdef IA64 -:MOV debugreg_x, Rmr32 is vexMode=0 & rexRprefix=1 & byte=0xf; byte=0x23; Rmr32 & debugreg_x & mod=3 { debugreg_x = zext(Rmr32); } :MOV debugreg, Rmr64 is $(LONGMODE_ON) & vexMode=0 & bit64=1 & byte=0xf; byte=0x23; Rmr64 & debugreg & mod=3 { debugreg = Rmr64; } :MOV debugreg_x, Rmr64 is $(LONGMODE_ON) & vexMode=0 & bit64=1 & rexRprefix=1 & byte=0xf; byte=0x23; Rmr64 & debugreg_x & mod=3 { debugreg_x = Rmr64; } @endif @@ -3284,7 +3307,7 @@ define pcodeop swap_bytes; :NEG Rmr64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0xf7; mod=3 & Rmr64 & reg_opcode=3 { negflags(Rmr64); Rmr64 = -Rmr64; resultflags(Rmr64); } @endif -:NOP is vexMode=0 & byte=0x90 & (mandover=0 | mandover=4) & (rexprefix=0 | rexWRXBprefix=8) { } +:NOP is vexMode=0 & byte=0x90 & (mandover=0 | mandover=4 | mandover=1) & (rexprefix=0 | rexWRXBprefix=8) { } :NOP rm16 is vexMode=0 & mandover & opsize=0 & byte=0x0f; high5=3; rm16 ... { } :NOP rm32 is vexMode=0 & mandover & opsize=1 & byte=0x0f; high5=3; rm32 ... { } :NOP^"/reserved" rm16 is vexMode=0 & mandover & opsize=0 & byte=0x0f; byte=0x18; rm16 & reg_opcode_hb=1 ... { } @@ -3350,17 +3373,17 @@ define pcodeop swap_bytes; :POP rm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x8f; rm32 & reg_opcode=0 ... { pop24(rm32); } :POP rm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x8f; rm32 & reg_opcode=0 ... { pop44(rm32); } @ifdef IA64 -:POP rm16 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & byte=0x8f; rm16 & reg_opcode=0 ... { pop82(rm16); } -:POP rm64 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0x8f; rm64 & reg_opcode=0 ... { pop88(rm64); } +:POP rm16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0x8f; rm16 & reg_opcode=0 ... { pop82(rm16); } +:POP rm64 is $(LONGMODE_ON) & vexMode=0 & byte=0x8f; rm64 & reg_opcode=0 ... { pop88(rm64); } @endif -:POP Rmr16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & row=5 & page=1 & Rmr16 { pop22(Rmr16); } -:POP Rmr16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & row=5 & page=1 & Rmr16 { pop42(Rmr16); } -:POP Rmr32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & row=5 & page=1 & Rmr32 { pop24(Rmr32); } -:POP Rmr32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & row=5 & page=1 & Rmr32 { pop44(Rmr32); } +:POP Rmr16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & row=5 & page=1 & Rmr16 { pop22(Rmr16); } +:POP Rmr16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & row=5 & page=1 & Rmr16 { pop42(Rmr16); } +:POP Rmr32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & row=5 & page=1 & Rmr32 { pop24(Rmr32); } +:POP Rmr32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & row=5 & page=1 & Rmr32 { pop44(Rmr32); } @ifdef IA64 -:POP Rmr16 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & row=5 & page=1 & Rmr16 { pop82(Rmr16); } -:POP Rmr64 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & row=5 & page=1 & Rmr64 { pop88(Rmr64); } +:POP Rmr16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & row=5 & page=1 & Rmr16 { pop82(Rmr16); } +:POP Rmr64 is $(LONGMODE_ON) & vexMode=0 & row=5 & page=1 & Rmr64 { pop88(Rmr64); } @endif :POP DS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0x1f & DS { pop22(DS); } @@ -3382,14 +3405,14 @@ define pcodeop swap_bytes; :POP GS is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0xa9 & GS { popseg88(GS); } @endif -:POPA is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x61 { pop22(DI); pop22(SI); pop22(BP); tmp:2=0; pop22(tmp); pop22(BX); pop22(DX); pop22(CX); pop22(AX); } -:POPA is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x61 { pop42(DI); pop42(SI); pop42(BP); tmp:2=0; pop42(tmp); pop42(BX); pop42(DX); pop42(CX); pop42(AX); } -:POPAD is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x61 { pop24(EDI); pop24(ESI); pop24(EBP); tmp:4=0; pop24(tmp); pop24(EBX); pop24(EDX); pop24(ECX); pop24(EAX); } -:POPAD is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x61 { pop44(EDI); pop44(ESI); pop44(EBP); tmp:4=0; pop44(tmp); pop44(EBX); pop44(EDX); pop44(ECX); pop44(EAX); } -:POPF is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x9d { pop22(flags); unpackflags(flags); } -:POPF is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x9d { pop42(flags); unpackflags(flags); } -:POPFD is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x9d { pop24(eflags); unpackflags(eflags); unpackeflags(eflags); } -:POPFD is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x9d { pop44(eflags); unpackflags(eflags); unpackeflags(eflags); } +:POPA is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x61 { pop22(DI); pop22(SI); pop22(BP); tmp:2=0; pop22(tmp); pop22(BX); pop22(DX); pop22(CX); pop22(AX); } +:POPA is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x61 { pop42(DI); pop42(SI); pop42(BP); tmp:2=0; pop42(tmp); pop42(BX); pop42(DX); pop42(CX); pop42(AX); } +:POPAD is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x61 { pop24(EDI); pop24(ESI); pop24(EBP); tmp:4=0; pop24(tmp); pop24(EBX); pop24(EDX); pop24(ECX); pop24(EAX); } +:POPAD is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x61 { pop44(EDI); pop44(ESI); pop44(EBP); tmp:4=0; pop44(tmp); pop44(EBX); pop44(EDX); pop44(ECX); pop44(EAX); } +:POPF is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x9d { pop22(flags); unpackflags(flags); } +:POPF is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x9d { pop42(flags); unpackflags(flags); } +:POPFD is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x9d { pop24(eflags); unpackflags(eflags); unpackeflags(eflags); } +:POPFD is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x9d { pop44(eflags); unpackflags(eflags); unpackeflags(eflags); } @ifdef IA64 :POPF is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & byte=0x9d { pop82(flags); unpackflags(flags); } :POPFQ is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0x9d { pop88(rflags); unpackflags(rflags); unpackeflags(rflags); } @@ -3409,78 +3432,75 @@ define pcodeop ptwrite; :PTWRITE rm32 is vexMode=0 & $(PRE_F3) & byte=0x0f; byte=0xae; rm32 & reg_opcode=4 ... { ptwrite(rm32); } + :PUSH rm16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0xff; rm16 & reg_opcode=6 ... { push22(rm16); } :PUSH rm16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0xff; rm16 & reg_opcode=6 ... { push42(rm16); } + :PUSH rm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0xff; rm32 & reg_opcode=6 ... { push24(rm32); } :PUSH rm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0xff; rm32 & reg_opcode=6 ... { push44(rm32); } @ifdef IA64 -:PUSH rm16 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & byte=0xff; rm16 & reg_opcode=6 ... { push82(rm16); } -:PUSH rm64 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0xff; rm64 & reg_opcode=6 ... { push88(rm64); } +:PUSH rm16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xff; rm16 & reg_opcode=6 ... { push82(rm16); } +:PUSH rm64 is $(LONGMODE_ON) & vexMode=0 & byte=0xff; rm64 & reg_opcode=6 ... { push88(rm64); } @endif + :PUSH Rmr16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & row=5 & page=0 & Rmr16 { push22(Rmr16); } :PUSH Rmr16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & row=5 & page=0 & Rmr16 { push42(Rmr16); } :PUSH Rmr32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & row=5 & page=0 & Rmr32 { push24(Rmr32); } :PUSH Rmr32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & row=5 & page=0 & Rmr32 { push44(Rmr32); } @ifdef IA64 -:PUSH Rmr16 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & row=5 & page=0 & Rmr16 { push82(Rmr16); } -:PUSH Rmr64 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & row=5 & page=0 & Rmr64 { push88(Rmr64); } -@endif -:PUSH simm8_16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x6a; simm8_16 { tmp:2=simm8_16; push22(tmp); } -:PUSH simm8_16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x6a; simm8_16 { tmp:2=simm8_16; push42(tmp); } -@ifdef IA64 -:PUSH simm8_16 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & byte=0x6a; simm8_16 { tmp:2=simm8_16; push82(tmp); } -@endif -:PUSH simm8_32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x6a; simm8_32 { tmp:4=simm8_32; push24(tmp); } -:PUSH simm8_32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x6a; simm8_32 { tmp:4=simm8_32; push44(tmp); } -@ifdef IA64 -:PUSH simm8_64 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=1 & byte=0x6a; simm8_64 { tmp:8=simm8_64; push88(tmp); } -:PUSH simm8_64 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=2 & byte=0x6a; simm8_64 { tmp:8=simm8_64; push88(tmp); } -@endif -:PUSH simm16_16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x68; simm16_16 { tmp:2=simm16_16; push22(tmp); } -:PUSH simm16_16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x68; simm16_16 { tmp:2=simm16_16; push42(tmp); } -@ifdef IA64 -:PUSH simm16_16 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & byte=0x68; simm16_16 { tmp:2=simm16_16; push82(tmp); } -@endif -:PUSH imm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x68; imm32 { tmp:4=imm32; push24(tmp); } -:PUSH imm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x68; imm32 { tmp:4=imm32; push44(tmp); } -@ifdef IA64 -:PUSH simm32 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=1 & byte=0x68; simm32 { tmp:8=simm32; push88(tmp); } -:PUSH simm32 is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=2 & byte=0x68; simm32 { tmp:8=simm32; push88(tmp); } +:PUSH Rmr16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & row=5 & page=0 & Rmr16 { push82(Rmr16); } +:PUSH Rmr64 is $(LONGMODE_ON) & vexMode=0 & row=5 & page=0 & Rmr64 { push88(Rmr64); } @endif -:PUSH CS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0xe & CS { push22(CS); } -:PUSH CS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0xe & CS { pushseg44(CS); } -:PUSH SS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0x16 & SS { push22(SS); } -:PUSH SS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0x16 & SS { pushseg44(SS); } -:PUSH DS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0x1e & DS { push22(DS); } -:PUSH DS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0x1e & DS { pushseg44(DS); } -:PUSH ES is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0x6 & ES { push22(ES); } -:PUSH ES is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0x6 & ES { pushseg44(ES); } -:PUSH FS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0xf; byte=0xa0 & FS { push22(FS); } -:PUSH FS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0xf; byte=0xa0 & FS { pushseg44(FS); } +:PUSH simm8_16 is $(LONGMODE_OFF) & vexMode=0 & opsize=0 & byte=0x6a; simm8_16 { tmp:2=simm8_16; push22(tmp); } +:PUSH simm8_32 is $(LONGMODE_OFF) & vexMode=0 & opsize=1 & byte=0x6a; simm8_32 { tmp:4=simm8_32; push44(tmp); } +@ifdef IA64 +:PUSH simm8_16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0x6a; simm8_16 { tmp:2=simm8_16; push82(tmp); } +:PUSH simm8_64 is $(LONGMODE_ON) & vexMode=0 & byte=0x6a; simm8_64 { tmp:8=simm8_64; push88(tmp); } +@endif + +:PUSH simm16_16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x68; simm16_16 { tmp:2=simm16_16; push22(tmp); } +:PUSH simm16_16 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x68; simm16_16 { tmp:2=simm16_16; push42(tmp); } +:PUSH imm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x68; imm32 { tmp:4=imm32; push24(tmp); } +:PUSH imm32 is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x68; imm32 { tmp:4=imm32; push44(tmp); } +@ifdef IA64 +:PUSH simm16_16 is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0x68; simm16_16 { tmp:2=simm16_16; push82(tmp); } +:PUSH simm32 is $(LONGMODE_ON) & vexMode=0 & byte=0x68; simm32 { tmp:8=simm32; push88(tmp); } +@endif + +:PUSH CS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0xe & CS { push22(CS); } +:PUSH CS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0xe & CS { pushseg44(CS); } +:PUSH SS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0x16 & SS { push22(SS); } +:PUSH SS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0x16 & SS { pushseg44(SS); } +:PUSH DS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0x1e & DS { push22(DS); } +:PUSH DS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0x1e & DS { pushseg44(DS); } +:PUSH ES is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0x6 & ES { push22(ES); } +:PUSH ES is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0x6 & ES { pushseg44(ES); } +:PUSH FS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0xf; byte=0xa0 & FS { push22(FS); } +:PUSH FS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0xf; byte=0xa0 & FS { pushseg44(FS); } @ifdef IA64 :PUSH FS is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xf; byte=0xa0 & FS { pushseg82(FS); } :PUSH FS is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0xa0 & FS { pushseg88(FS); } @endif -:PUSH GS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0xf; byte=0xa8 & GS { push22(GS); } -:PUSH GS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0xf; byte=0xa8 & GS { pushseg44(GS); } +:PUSH GS is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & byte=0xf; byte=0xa8 & GS { push22(GS); } +:PUSH GS is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & byte=0xf; byte=0xa8 & GS { pushseg44(GS); } @ifdef IA64 :PUSH GS is $(LONGMODE_ON) & vexMode=0 & opsize=0 & byte=0xf; byte=0xa8 & GS { pushseg82(GS); } :PUSH GS is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0xa8 & GS { pushseg88(GS); } @endif -:PUSHA is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x60 { local tmp=SP; push22(AX); push22(CX); push22(DX); push22(BX); push22(tmp); push22(BP); push22(SI); push22(DI); } -:PUSHA is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x60 { local tmp=SP; push42(AX); push42(CX); push42(DX); push42(BX); push42(tmp); push42(BP); push42(SI); push42(DI); } -:PUSHAD is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x60 { local tmp=ESP; push24(EAX); push24(ECX); push24(EDX); push24(EBX); push24(tmp); push24(EBP); push24(ESI); push24(EDI); } -:PUSHAD is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x60 { local tmp=ESP; push44(EAX); push44(ECX); push44(EDX); push44(EBX); push44(tmp); push44(EBP); push44(ESI); push44(EDI); } +:PUSHA is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x60 { local tmp=SP; push22(AX); push22(CX); push22(DX); push22(BX); push22(tmp); push22(BP); push22(SI); push22(DI); } +:PUSHA is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x60 { local tmp=SP; push42(AX); push42(CX); push42(DX); push42(BX); push42(tmp); push42(BP); push42(SI); push42(DI); } +:PUSHAD is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x60 { local tmp=ESP; push24(EAX); push24(ECX); push24(EDX); push24(EBX); push24(tmp); push24(EBP); push24(ESI); push24(EDI); } +:PUSHAD is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x60 { local tmp=ESP; push44(EAX); push44(ECX); push44(EDX); push44(EBX); push44(tmp); push44(EBP); push44(ESI); push44(EDI); } -:PUSHF is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x9c { packflags(flags); push22(flags); } -:PUSHF is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x9c { packflags(flags); push42(flags); } -:PUSHFD is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x9c { packflags(eflags); packeflags(eflags); push24(eflags); } -:PUSHFD is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x9c { packflags(eflags); packeflags(eflags); push44(eflags); } +:PUSHF is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=0 & byte=0x9c { packflags(flags); push22(flags); } +:PUSHF is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=0 & byte=0x9c { packflags(flags); push42(flags); } +:PUSHFD is $(LONGMODE_OFF) & vexMode=0 & addrsize=0 & opsize=1 & byte=0x9c { packflags(eflags); packeflags(eflags); push24(eflags); } +:PUSHFD is $(LONGMODE_OFF) & vexMode=0 & addrsize=1 & opsize=1 & byte=0x9c { packflags(eflags); packeflags(eflags); push44(eflags); } @ifdef IA64 :PUSHF is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=0 & byte=0x9c { packflags(flags); push82(flags); } -:PUSHFQ is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & byte=0x9c { packflags(rflags); packeflags(rflags); push88(rflags); } +:PUSHFQ is $(LONGMODE_ON) & vexMode=0 & byte=0x9c { packflags(rflags); packeflags(rflags); push88(rflags); } @endif :RCL rm8,n1 is vexMode=0 & byte=0xD0; rm8 & n1 & reg_opcode=2 ... { local tmpCF = CF; CF = rm8 s< 0; rm8 = (rm8 << 1) | tmpCF; OF = CF ^ (rm8 s< 0); } @@ -3696,18 +3716,18 @@ define pcodeop smm_restore_state; :SET^cc rm8 is vexMode=0 & byte=0xf; row=9 & cc; rm8 { rm8 = cc; } # manual is not consistent on operands -:SGDT m16 is vexMode=0 & opsize=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=0 ) ... & m16 +:SGDT m16 is $(LONGMODE_OFF) & vexMode=0 & opsize=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=0 ) ... & m16 { m16 = GlobalDescriptorTableRegister(); } -:SGDT m32 is vexMode=0 & opsize=1 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=0 ) ... & m32 +:SGDT m32 is $(LONGMODE_OFF) & vexMode=0 & opsize=1 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=0 ) ... & m32 { m32 = GlobalDescriptorTableRegister(); } @ifdef IA64 -:SGDT m64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=0 ) ... & m64 +:SGDT m64 is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=0 ) ... & m64 { m64 = GlobalDescriptorTableRegister(); } @@ -3802,17 +3822,17 @@ define pcodeop smm_restore_state; shrflags(tmp, rm64,count); shiftresultflags(rm64,count); } @endif -:SIDT m16 is vexMode=0 & opsize=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=1 ) ... & m16 +:SIDT m16 is $(LONGMODE_OFF) & vexMode=0 & opsize=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=1 ) ... & m16 { m16 = InterruptDescriptorTableRegister(); } -:SIDT m32 is vexMode=0 & opsize=1 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=1 ) ... & m32 +:SIDT m32 is $(LONGMODE_OFF) & vexMode=0 & opsize=1 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=1 ) ... & m32 { m32 = InterruptDescriptorTableRegister(); } @ifdef IA64 -:SIDT m64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=1 ) ... & m64 +:SIDT m64 is $(LONGMODE_ON) & vexMode=0 & byte=0xf; byte=0x1; ( mod != 0b11 & reg_opcode=1 ) ... & m64 { m64 = InterruptDescriptorTableRegister(); } @@ -4497,10 +4517,10 @@ define pcodeop fsin; :FXCH freg is vexMode=0 & byte=0xD9; frow=12 & fpage=1 & freg { local tmp = ST0; ST0 = freg; freg = tmp; } :FXCH is vexMode=0 & byte=0xD9; byte=0xC9 { local tmp = ST0; ST0 = ST1; ST1 = tmp; } -@ifndef IA64 -# this saves the FPU state into 512 bytes of memory similar to the 32-bit mode -:FXSAVE Mem is vexMode=0 & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=0 ) ... & Mem -{ +# fxsave and fxrstor + +@ifdef ICICLE +macro _fxsave(Mem) { # not saved in the same spacing as the actual processor *:2 (Mem) = FPUControlWord; *:2 (Mem + 2) = FPUStatusWord; @@ -4531,98 +4551,24 @@ define pcodeop fsin; *:16 (Mem + 240) = XMM5; *:16 (Mem + 256) = XMM6; *:16 (Mem + 272) = XMM7; +@ifdef IA64 + *:16 (Mem + 288) = XMM8; + *:16 (Mem + 304) = XMM9; + *:16 (Mem + 320) = XMM10; + *:16 (Mem + 336) = XMM11; + *:16 (Mem + 352) = XMM12; + *:16 (Mem + 368) = XMM13; + *:16 (Mem + 384) = XMM14; + *:16 (Mem + 400) = XMM15; +@endif } - @else -# this saves the FPU state into 512 bytes of memory similar to the 32-bit mode -:FXSAVE Mem is vexMode=0 & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=0 ) ... & Mem -{ - *:2 (Mem) = FPUControlWord; - *:2 (Mem + 2) = FPUStatusWord; - *:2 (Mem + 4) = FPUTagWord; #The real implementation saves an 'abridged' tag word, but that is a non-trivial operation - *:2 (Mem + 6) = FPULastInstructionOpcode; - *:4 (Mem + 8) = FPUInstructionPointer; - *:2 (Mem + 12) = FPUPointerSelector; - *:4 (Mem + 16) = FPUDataPointer; - *:2 (Mem + 20) = FPUDataSelector; - *:4 (Mem + 24) = MXCSR; - # MXCSR_MASK not modeled, since it is processor specific, set to 0. - - -# saved the FPU ST registers to the ST/MM area of the structure, - *:10 (Mem + 32) = ST0; - *:10 (Mem + 48) = ST1; - *:10 (Mem + 64) = ST2; - *:10 (Mem + 80) = ST3; - *:10 (Mem + 96) = ST4; - *:10 (Mem + 112) = ST5; - *:10 (Mem + 128) = ST6; - *:10 (Mem + 144) = ST7; - - *:16 (Mem + 160) = XMM0; - *:16 (Mem + 176) = XMM1; - *:16 (Mem + 192) = XMM2; - *:16 (Mem + 208) = XMM3; - *:16 (Mem + 224) = XMM4; - *:16 (Mem + 240) = XMM5; - *:16 (Mem + 256) = XMM6; - *:16 (Mem + 272) = XMM7; - *:16 (Mem + 288) = XMM8; - *:16 (Mem + 304) = XMM9; - *:16 (Mem + 320) = XMM10; - *:16 (Mem + 336) = XMM11; - *:16 (Mem + 352) = XMM12; - *:16 (Mem + 368) = XMM13; - *:16 (Mem + 384) = XMM14; - *:16 (Mem + 400) = XMM15; -} - -# this saves the FPU state into 512 bytes of memory similar to the 32-bit mode -:FXSAVE64 Mem is vexMode=0 & $(REX_W) & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=0 ) ... & Mem -{ - *:2 (Mem) = FPUControlWord; - *:2 (Mem + 2) = FPUStatusWord; - *:2 (Mem + 4) = FPUTagWord; #The real implementation saves an 'abridged' tag word, but that is a non-trivial operation - *:2 (Mem + 6) = FPULastInstructionOpcode; - *:8 (Mem + 8) = FPUInstructionPointer; - *:8 (Mem + 16) = FPUDataPointer; - *:4 (Mem + 24) = MXCSR; - # MXCSR_MASK not modeled, since it is processor specific, set to 0. - -# saved the FPU ST registers to the ST/MM area of the structure, - *:10 (Mem + 32) = ST0; - *:10 (Mem + 48) = ST1; - *:10 (Mem + 64) = ST2; - *:10 (Mem + 80) = ST3; - *:10 (Mem + 96) = ST4; - *:10 (Mem + 112) = ST5; - *:10 (Mem + 128) = ST6; - *:10 (Mem + 144) = ST7; - - - *:16 (Mem + 160) = XMM0; - *:16 (Mem + 176) = XMM1; - *:16 (Mem + 192) = XMM2; - *:16 (Mem + 208) = XMM3; - *:16 (Mem + 224) = XMM4; - *:16 (Mem + 240) = XMM5; - *:16 (Mem + 256) = XMM6; - *:16 (Mem + 272) = XMM7; - *:16 (Mem + 288) = XMM8; - *:16 (Mem + 304) = XMM9; - *:16 (Mem + 320) = XMM10; - *:16 (Mem + 336) = XMM11; - *:16 (Mem + 352) = XMM12; - *:16 (Mem + 368) = XMM13; - *:16 (Mem + 384) = XMM14; - *:16 (Mem + 400) = XMM15; -} +define pcodeop _fxsave; @endif -@ifndef IA64 -:FXRSTOR Mem is vexMode=0 & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=1 ) ... & Mem -{ - FPUControlWord = *:2 (Mem); +@ifdef ICICLE +macro _fxrstor(Mem) { +FPUControlWord = *:2 (Mem); FPUStatusWord = *:2 (Mem + 2); FPUTagWord = *:2 (Mem + 4); #The real implementation saves an 'abridged' tag word, but that is a non-trivial operation FPULastInstructionOpcode = *:2 (Mem + 6); @@ -4643,6 +4589,7 @@ define pcodeop fsin; ST6 = *:10 (Mem + 128); ST7 = *:10 (Mem + 144); + XMM0 = *:16 (Mem + 160); XMM1 = *:16 (Mem + 176); XMM2 = *:16 (Mem + 192); @@ -4651,88 +4598,57 @@ define pcodeop fsin; XMM5 = *:16 (Mem + 240); XMM6 = *:16 (Mem + 256); XMM7 = *:16 (Mem + 272); +@ifdef IA64 + XMM8 = *:16 (Mem + 288); + XMM9 = *:16 (Mem + 304); + XMM10 = *:16 (Mem + 320); + XMM11 = *:16 (Mem + 336); + XMM12 = *:16 (Mem + 352); + XMM13 = *:16 (Mem + 368); + XMM14 = *:16 (Mem + 384); + XMM15 = *:16 (Mem + 400); +@endif } - @else -:FXRSTOR64 Mem is vexMode=0 & $(REX_W) & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=1 ) ... & Mem +define pcodeop _fxrstor; +@endif + +@ifdef IA64 +define pcodeop _fxsave64; +define pcodeop _fxrstor64; +@endif + +# this saves the FPU state into 512 bytes of memory +:FXSAVE Mem is $(LONGMODE_OFF) & vexMode=0 & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=0 ) ... & Mem { - FPUControlWord = *:2 (Mem); - FPUStatusWord = *:2 (Mem + 2); - FPUTagWord = *:2 (Mem + 4); #The real implementation saves an 'abridged' tag word, but that is a non-trivial operation - FPULastInstructionOpcode = *:2 (Mem + 6); - FPUInstructionPointer = *:8 (Mem + 8); - FPUDataPointer = *:8 (Mem + 16); - MXCSR = *:4 (Mem + 24); - # MXCSR_MASK not modeled, since it is processor specific, set to 0. - -# saved the FPU ST registers to the ST/MM area of the structure, - ST0 = *:10 (Mem + 32); - ST1 = *:10 (Mem + 48); - ST2 = *:10 (Mem + 64); - ST3 = *:10 (Mem + 80); - ST4 = *:10 (Mem + 96); - ST5 = *:10 (Mem + 112); - ST6 = *:10 (Mem + 128); - ST7 = *:10 (Mem + 144); - - XMM0 = *:16 (Mem + 160); - XMM1 = *:16 (Mem + 176); - XMM2 = *:16 (Mem + 192); - XMM3 = *:16 (Mem + 208); - XMM4 = *:16 (Mem + 224); - XMM5 = *:16 (Mem + 240); - XMM6 = *:16 (Mem + 256); - XMM7 = *:16 (Mem + 272); - XMM8 = *:16 (Mem + 288); - XMM9 = *:16 (Mem + 304); - XMM10 = *:16 (Mem + 320); - XMM11 = *:16 (Mem + 336); - XMM12 = *:16 (Mem + 352); - XMM13 = *:16 (Mem + 368); - XMM14 = *:16 (Mem + 384); - XMM15 = *:16 (Mem + 400); + _fxsave(Mem); } -:FXRSTOR Mem is vexMode=0 & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=1 ) ... & Mem +:FXRSTOR Mem is $(LONGMODE_OFF) & vexMode=0 & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=1 ) ... & Mem { - FPUControlWord = *:2 (Mem); - FPUStatusWord = *:2 (Mem + 2); - FPUTagWord = *:2 (Mem + 4); #The real implementation saves an 'abridged' tag word, but that is a non-trivial operation - FPULastInstructionOpcode = *:2 (Mem + 6); - FPUInstructionPointer = *:4 (Mem + 8); - FPUPointerSelector = *:2 (Mem + 12); - FPUDataPointer = *:4 (Mem + 16); - FPUDataSelector = *:2 (Mem + 20); - MXCSR = *:4 (Mem + 24); - # MXCSR_MASK not modeled, since it is processor specific, set to 0. + _fxrstor(Mem); +} -# saved the FPU ST registers to the ST/MM area of the structure, - ST0 = *:10 (Mem + 32); - ST1 = *:10 (Mem + 48); - ST2 = *:10 (Mem + 64); - ST3 = *:10 (Mem + 80); - ST4 = *:10 (Mem + 96); - ST5 = *:10 (Mem + 112); - ST6 = *:10 (Mem + 128); - ST7 = *:10 (Mem + 144); +@ifdef IA64 +# this saves the FPU state into 512 bytes of memory similar to the 32-bit mode +:FXSAVE Mem is $(LONGMODE_ON) & vexMode=0 & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=0 ) ... & Mem +{ + _fxsave(Mem); +} +:FXSAVE64 Mem is $(LONGMODE_ON) & vexMode=0 & $(REX_W) & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=0 ) ... & Mem +{ + _fxsave64(Mem); +} - XMM0 = *:16 (Mem + 160); - XMM1 = *:16 (Mem + 176); - XMM2 = *:16 (Mem + 192); - XMM3 = *:16 (Mem + 208); - XMM4 = *:16 (Mem + 224); - XMM5 = *:16 (Mem + 240); - XMM6 = *:16 (Mem + 256); - XMM7 = *:16 (Mem + 272); - XMM8 = *:16 (Mem + 288); - XMM9 = *:16 (Mem + 304); - XMM10 = *:16 (Mem + 320); - XMM11 = *:16 (Mem + 336); - XMM12 = *:16 (Mem + 352); - XMM13 = *:16 (Mem + 368); - XMM14 = *:16 (Mem + 384); - XMM15 = *:16 (Mem + 400); +:FXRSTOR Mem is $(LONGMODE_ON) & vexMode=0 & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=1 ) ... & Mem +{ + _fxrstor(Mem); +} + +:FXRSTOR64 Mem is $(LONGMODE_ON) & vexMode=0 & $(REX_W) & byte=0x0F; byte=0xAE; ( mod != 0b11 & reg_opcode=1 ) ... & Mem +{ + _fxrstor64(Mem); } @endif @@ -8834,9 +8750,10 @@ define pcodeop pmovzxdq; :PMOVZXDQ XmmReg1, XmmReg2 is vexMode=0 & $(PRE_66) & byte=0x0F; byte=0x38; byte=0x35; xmmmod=3 & XmmReg1 & XmmReg2 { XmmReg1 = pmovzxdq(XmmReg1, XmmReg2); } :PTEST XmmReg, m128 is vexMode=0 & $(PRE_66) & byte=0x0F; byte=0x38; byte=0x17; XmmReg ... & m128 { - local tmp = m128 & XmmReg; + local temp_m128:16 = m128; + local tmp = temp_m128 & XmmReg; ZF = tmp == 0; - local tmp2 = m128 & ~XmmReg; + local tmp2 = temp_m128 & ~XmmReg; CF = tmp2 == 0; AF = 0; OF = 0; @@ -8857,8 +8774,9 @@ define pcodeop pmovzxdq; :PCMPEQQ XmmReg, m128 is vexMode=0 & $(PRE_66) & byte=0x0F; byte=0x38; byte=0x29; XmmReg ... & m128 { - XmmReg[0,64] = zext(XmmReg[0,64] == m128[0,64]) * 0xffffffffffffffff:8; - XmmReg[64,64] = zext(XmmReg[64,64] == m128[64,64]) * 0xffffffffffffffff:8; + local temp_m128:16 = m128; + XmmReg[0,64] = zext(XmmReg[0,64] == temp_m128[0,64]) * 0xffffffffffffffff:8; + XmmReg[64,64] = zext(XmmReg[64,64] == temp_m128[64,64]) * 0xffffffffffffffff:8; } :PCMPEQQ XmmReg1, XmmReg2 is vexMode=0 & $(PRE_66) & byte=0x0F; byte=0x38; byte=0x29; xmmmod=3 & XmmReg1 & XmmReg2 { diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/lockable.sinc b/src/icicle/data/Ghidra/Processors/x86/data/languages/lockable.sinc index be1876b1..6b7bfa53 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/lockable.sinc +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/lockable.sinc @@ -575,43 +575,48 @@ :CMPXCHG^lockx m8,Reg8 is vexMode=0 & lockx & unlock & byte=0xf; byte=0xb0; m8 & Reg8 ... { build lockx; - build m8; - subflags(AL,m8); - local tmp=AL-m8; - resultflags(tmp); - local diff = m8^Reg8; - m8 = m8 ^ (ZF*diff); - diff = AL ^ m8; AL = AL ^ ((ZF==0)*diff); - build unlock; + local dest = m8; + subflags(AL,dest); + local diff = AL-dest; + resultflags(diff); + if (ZF) goto ; + AL = dest; + goto ; + + m8 = Reg8; + + build unlock; } :CMPXCHG^lockx m16,Reg16 is vexMode=0 & lockx & unlock & opsize=0 & byte=0xf; byte=0xb1; m16 & Reg16 ... { build lockx; - build m16; - subflags(AX,m16); - local tmp=AX-m16; - resultflags(tmp); - local diff = m16^Reg16; - m16 = m16 ^ (zext(ZF) * diff); - diff = AX ^ m16; - AX = AX ^ (zext(ZF==0) * diff); + local dest = m16; + subflags(AX,dest); + local diff = AX-dest; + resultflags(diff); + if (ZF) goto ; + AX = dest; + goto ; + + m16 = Reg16; + build unlock; } :CMPXCHG^lockx m32,Reg32 is vexMode=0 & lockx & unlock & opsize=1 & byte=0xf; byte=0xb1; m32 & Reg32 ... & check_EAX_dest ... { build lockx; - build m32; - #this instruction writes to either EAX or m32 - #in 64-bit mode, a 32-bit register that is written to - #(and only the register that is written to) + #this instruction writes to either EAX or Rmr32 + #in 64-bit mode, a 32-bit register that is written to + #(and only the register that is written to) #must be zero-extended to 64 bits - subflags(EAX,m32); - local tmp=EAX-m32; - resultflags(tmp); - if (ZF==1) goto ; - EAX = m32; + local dest = m32; + subflags(EAX,dest); + local diff = EAX-dest; + resultflags(diff); + if (ZF) goto ; + EAX = dest; build check_EAX_dest; goto ; @@ -624,26 +629,28 @@ :CMPXCHG^lockx m64,Reg64 is $(LONGMODE_ON) & vexMode=0 & lockx & unlock & opsize=2 & byte=0xf; byte=0xb1; m64 & Reg64 ... { build lockx; - build m64; - subflags(RAX,m64); - local tmp=RAX-m64; - resultflags(tmp); - local diff = m64^Reg64; - m64 = m64 ^ (zext(ZF) * diff); - diff = RAX ^ m64; - RAX = RAX ^ (zext(ZF==0) * diff); - build unlock; + local dest = m64; + subflags(RAX,dest); + local diff = RAX-dest; + resultflags(diff); + if (ZF) goto ; + RAX = dest; + goto ; + + m64 = Reg64; + + build unlock; } @endif :CMPXCHG8B^lockx m64 is vexMode=0 & lockx & unlock & byte=0xf; byte=0xc7; ( mod != 0b11 & reg_opcode=1 ) ... & m64 { build lockx; - build m64; - ZF = ((zext(EDX) << 32) | zext(EAX)) == m64; + local dest = m64; + ZF = ((zext(EDX) << 32) | zext(EAX)) == dest; if (ZF == 1) goto ; - EDX = m64(4); - EAX = m64:4; + EDX = dest(4); + EAX = dest:4; goto ; m64 = (zext(ECX) << 32) | zext(EBX); @@ -654,11 +661,11 @@ @ifdef IA64 :CMPXCHG16B^lockx m128 is $(LONGMODE_ON) & vexMode=0 & lockx & unlock & opsize=2 & byte=0xf; byte=0xc7; ( mod != 0b11 & reg_opcode=1 ) ... & ( m128 ) { build lockx; - build m128; - ZF = ((zext(RDX) << 64) | zext(RAX)) == m128; + local dest = m128; + ZF = ((zext(RDX) << 64) | zext(RAX)) == dest; if (ZF == 1) goto ; - RDX = m128(8); - RAX = m128:8; + RDX = dest(8); + RAX = dest:8; goto ; m128 = ((zext(RCX) << 64) | zext(RBX)); diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/macros.sinc b/src/icicle/data/Ghidra/Processors/x86/data/languages/macros.sinc index 1a199e1a..be1373d2 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/macros.sinc +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/macros.sinc @@ -1,3 +1,3 @@ macro conditionalAssign(dest, cond, trueVal, falseVal) { dest = zext(cond) * trueVal | zext(!cond) * falseVal; -} \ No newline at end of file +} diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-32-golang.cspec b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-32-golang.cspec new file mode 100644 index 00000000..0087f87e --- /dev/null +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-32-golang.cspec @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-32-golang.register.info b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-32-golang.register.info new file mode 100644 index 00000000..bd549e63 --- /dev/null +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-32-golang.register.info @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-compat32.pspec b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-compat32.pspec new file mode 100644 index 00000000..51ba63c8 --- /dev/null +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-compat32.pspec @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-gcc.cspec b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-gcc.cspec index 7b7ca230..df20e918 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-gcc.cspec +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-gcc.cspec @@ -239,4 +239,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-golang.cspec b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-golang.cspec new file mode 100644 index 00000000..8196a9a6 --- /dev/null +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-golang.cspec @@ -0,0 +1,428 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-golang.register.info b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-golang.register.info new file mode 100644 index 00000000..b0f5bb71 --- /dev/null +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-golang.register.info @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-win.cspec b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-win.cspec index 907f9814..d0a77426 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-win.cspec +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64-win.cspec @@ -201,6 +201,7 @@ + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64.pspec b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64.pspec index 315344dc..08cefc96 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64.pspec +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86-64.pspec @@ -9,7 +9,6 @@ - diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86.ldefs b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86.ldefs index 482ef9e3..1961485c 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86.ldefs +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86.ldefs @@ -16,6 +16,7 @@ + @@ -28,6 +29,7 @@ + - + - - + + + + + + Intel/AMD 64-bit x86 in 32-bit compatibility mode (long mode off) + + + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86.opinion b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86.opinion index ef5283f7..bca1e2d2 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86.opinion +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86.opinion @@ -1,16 +1,17 @@ + - + - + @@ -22,16 +23,20 @@ + + + + - + - + @@ -47,18 +52,18 @@ - + - + - + - + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86gcc.cspec b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86gcc.cspec index bcd049d2..0cda278b 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86gcc.cspec +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86gcc.cspec @@ -331,6 +331,17 @@ + + + + + + + + @@ -364,7 +375,7 @@ - + @@ -374,4 +385,79 @@ ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86win.cspec b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86win.cspec index c07b7e4d..e61b3ada 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/x86win.cspec +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/x86win.cspec @@ -19,7 +19,7 @@ - + @@ -377,4 +377,12 @@ + + + + + + From 1ed997445d317ddfdf5f35cde160123f26a58689 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 6 Apr 2025 20:17:39 +0200 Subject: [PATCH 17/21] Fix IRETQ instruction --- src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc b/src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc index 19edb19c..26dfefa2 100644 --- a/src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc +++ b/src/icicle/data/Ghidra/Processors/x86/data/languages/ia.sinc @@ -2866,7 +2866,7 @@ enterFrames: low5 is low5 { tmp:1 = low5; export tmp; } :IRETD is vexMode=0 & addrsize=1 & opsize=1 & byte=0xcf { pop44(EIP); tmp:4=0; pop44(tmp); CS=tmp(0); pop44(eflags); return [EIP]; } @ifdef IA64 :IRETD is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=1 & byte=0xcf { pop84(EIP); RIP=zext(EIP); tmp:4=0; pop84(tmp); CS=tmp(0); pop84(eflags); return [RIP]; } -:IRETQ is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=2 & byte=0xcf { pop88(RIP); tmp:8=0; pop88(tmp); CS=tmp(0); pop88(rflags); return [RIP]; } +:IRETQ is $(LONGMODE_ON) & vexMode=0 & addrsize=2 & opsize=2 & byte=0xcf { pop88(RIP); tmp:8=0; pop88(tmp); CS=tmp(0); pop88(rflags); pop88(RSP); return [RIP]; } @endif :J^cc rel8 is vexMode=0 & row=7 & cc; rel8 { if (cc) goto rel8; } From baad36ccf20264f4ba031e96ba9a4aab2fceb8e9 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 7 Apr 2025 07:24:46 +0200 Subject: [PATCH 18/21] Support interrupt hooks --- src/icicle-emulator/icicle_x64_emulator.cpp | 21 +++++++++++++++------ src/icicle/src/icicle.rs | 20 +++++++++++++++++++- src/icicle/src/lib.rs | 11 +++++++++++ 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index 77101bc5..8e6aa4b0 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -12,6 +12,7 @@ extern "C" using raw_func = void(void*); using ptr_func = void(void*, uint64_t); + using interrupt_func = void(void*, int32_t); using violation_func = int32_t(void*, uint64_t address, uint8_t operation, int32_t unmapped); using data_accessor_func = void(void* user, const void* data, size_t length); using memory_access_func = icicle_mmio_write_func; @@ -27,6 +28,7 @@ extern "C" int32_t icicle_save_registers(icicle_emulator*, data_accessor_func* accessor, void* accessor_data); int32_t icicle_restore_registers(icicle_emulator*, const void* data, size_t length); uint32_t icicle_add_syscall_hook(icicle_emulator*, raw_func* callback, void* data); + uint32_t icicle_add_interrupt_hook(icicle_emulator*, interrupt_func* callback, void* data); uint32_t icicle_add_execution_hook(icicle_emulator*, uint64_t address, ptr_func* callback, void* data); uint32_t icicle_add_generic_execution_hook(icicle_emulator*, ptr_func* callback, void* data); uint32_t icicle_add_violation_hook(icicle_emulator*, violation_func* callback, void* data); @@ -260,10 +262,17 @@ namespace icicle emulator_hook* hook_interrupt(interrupt_hook_callback callback) override { - // TODO - (void)callback; - return nullptr; - // throw std::runtime_error("Not implemented"); + auto obj = make_function_object(std::move(callback)); + auto* ptr = obj.get(); + auto* wrapper = +[](void* user, const int32_t code) { + const auto& func = *static_cast(user); + func(code); + }; + + const auto id = icicle_add_interrupt_hook(this->emu_, wrapper, ptr); + this->hooks_[id] = std::move(obj); + + return wrap_hook(id); } emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) override @@ -292,7 +301,7 @@ namespace icicle auto object = make_function_object(std::move(callback)); auto* ptr = object.get(); auto* wrapper = +[](void* user, const uint64_t addr) { - auto& func = *static_cast(user); + const auto& func = *static_cast(user); (func)(addr); }; @@ -307,7 +316,7 @@ namespace icicle auto object = make_function_object(std::move(callback)); auto* ptr = object.get(); auto* wrapper = +[](void* user, const uint64_t addr) { - auto& func = *static_cast(user); + const auto& func = *static_cast(user); (func)(addr); }; diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index ac0e4c9c..c601ce09 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -49,6 +49,7 @@ enum HookType { ExecuteGeneric, ExecuteSpecific, Violation, + Interrupt, Unknown, } @@ -216,6 +217,7 @@ pub struct IcicleEmulator { vm: icicle_vm::Vm, reg: registers::X64RegisterNodes, syscall_hooks: HookContainer, + interrupt_hooks: HookContainer, violation_hooks: HookContainer bool>, execution_hooks: Rc>, stop: Rc>, @@ -287,6 +289,7 @@ impl IcicleEmulator { reg: registers::X64RegisterNodes::new(&virtual_machine.cpu.arch), vm: virtual_machine, syscall_hooks: HookContainer::new(), + interrupt_hooks: HookContainer::new(), violation_hooks: HookContainer::new(), execution_hooks: exec_hooks, } @@ -326,6 +329,14 @@ impl IcicleEmulator { } } + fn handle_interrupt(&self, code: i32) -> bool { + for (_key, func) in self.interrupt_hooks.get_hooks() { + func(code); + } + + return true; + } + fn handle_exception(&mut self, code: ExceptionCode, value: u64) -> bool { let continue_execution = match code { ExceptionCode::Syscall => self.handle_syscall(), @@ -333,7 +344,8 @@ impl IcicleEmulator { ExceptionCode::WritePerm => self.handle_violation(value, FOREIGN_WRITE, false), ExceptionCode::ReadUnmapped => self.handle_violation(value, FOREIGN_READ, true), ExceptionCode::WriteUnmapped => self.handle_violation(value, FOREIGN_WRITE, true), - ExceptionCode::ExecViolation => self.handle_violation(value, FOREIGN_EXEC, true), + ExceptionCode::InvalidInstruction => self.handle_interrupt(6), + ExceptionCode::DivisionException => self.handle_interrupt(0), _ => false, }; @@ -392,6 +404,11 @@ impl IcicleEmulator { return qualify_hook_id(hook_id, HookType::Syscall); } + pub fn add_interrupt_hook(&mut self, callback: Box) -> u32 { + let hook_id = self.interrupt_hooks.add_hook(callback); + return qualify_hook_id(hook_id, HookType::Interrupt); + } + pub fn add_read_hook( &mut self, start: u64, @@ -426,6 +443,7 @@ impl IcicleEmulator { match hook_type { HookType::Syscall => self.syscall_hooks.remove_hook(hook_id), HookType::Violation => self.violation_hooks.remove_hook(hook_id), + HookType::Interrupt => self.interrupt_hooks.remove_hook(hook_id), HookType::ExecuteGeneric => self.execution_hooks.borrow_mut().remove_generic_hook(hook_id), HookType::ExecuteSpecific => self.execution_hooks.borrow_mut().remove_specific_hook(hook_id), HookType::Read => {self.get_mem().remove_read_after_hook(hook_id);()}, diff --git a/src/icicle/src/lib.rs b/src/icicle/src/lib.rs index a494b806..19706c0f 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -41,6 +41,7 @@ type DataFunction = extern "C" fn(*mut c_void, *const c_void, usize); type MmioReadFunction = extern "C" fn(*mut c_void, u64, *mut c_void, usize); type MmioWriteFunction = extern "C" fn(*mut c_void, u64, *const c_void, usize); type ViolationFunction = extern "C" fn(*mut c_void, u64, u8, i32) -> i32; +type InterruptFunction = extern "C" fn(*mut c_void, i32); type MemoryAccessFunction = MmioWriteFunction; #[unsafe(no_mangle)] @@ -165,6 +166,16 @@ pub fn icicle_read_memory(ptr: *mut c_void, address: u64, data: *mut c_void, siz } } +#[unsafe(no_mangle)] +pub fn icicle_add_interrupt_hook(ptr: *mut c_void, callback: InterruptFunction, data: *mut c_void) -> u32 { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + return emulator.add_interrupt_hook(Box::new( + move |code: i32| callback(data, code), + )); + } +} + #[unsafe(no_mangle)] pub fn icicle_add_violation_hook(ptr: *mut c_void, callback: ViolationFunction, data: *mut c_void) -> u32 { unsafe { From 787410ff332882b5add5cf2c8eac5dcf6d8b0710 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 7 Apr 2025 07:35:08 +0200 Subject: [PATCH 19/21] Remove IP skip check --- src/icicle/src/icicle.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index c601ce09..5a25d445 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -131,7 +131,6 @@ impl icicle_vm::CodeInjector for InstructionHookInjector { } struct ExecutionHooks { - skip_ip: Option, stop: Rc>, generic_hooks: HookContainer, specific_hooks: HookContainer, @@ -141,7 +140,6 @@ struct ExecutionHooks { impl ExecutionHooks { pub fn new(stop_value: Rc>) -> Self { Self { - skip_ip: None, stop: stop_value, generic_hooks: HookContainer::new(), specific_hooks: HookContainer::new(), @@ -168,18 +166,9 @@ impl ExecutionHooks { } pub fn execute(&mut self,cpu: &mut icicle_cpu::Cpu, address: u64) { - let mut skip = false; - if self.skip_ip.is_some() { - skip = self.skip_ip.unwrap() == address; - self.skip_ip = None; - } - - if !skip { - self.run_hooks(address); - } + self.run_hooks(address); if *self.stop.borrow() { - self.skip_ip = Some(address); cpu.exception.code = ExceptionCode::InstructionLimit as u32; cpu.exception.value = address; } From 1cfe20b7a12badf395ed3658c1bd3d48705d8188 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 7 Apr 2025 08:04:24 +0200 Subject: [PATCH 20/21] Skip icicle debug tests --- .github/workflows/build.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2afb2310..4993b209 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,14 @@ on: options: - "true" - "false" + icicle_debug: + description: "Run debug tests with icicle emulator" + type: choice + required: false + default: "false" + options: + - "true" + - "false" #concurrency: # group: ${{ github.ref }} @@ -336,6 +344,7 @@ jobs: run: cp build/${{matrix.preset}}/artifacts/test-sample.exe build/${{matrix.preset}}/artifacts/root/filesys/c/ - name: CMake Test + if: "${{ matrix.emulator != 'Icicle' || matrix.configuration != 'Debug' || github.event.inputs.icicle_debug == 'true' || github.event.inputs.icicle_debug == 'true' || github.event_name == 'schedule' }}" run: cd build/${{matrix.preset}} && ctest --verbose -j env: EMULATOR_ROOT: ${{github.workspace}}/build/${{matrix.preset}}/artifacts/root @@ -401,6 +410,7 @@ jobs: run: cp build/${{matrix.preset}}/artifacts/test-sample.exe build/${{matrix.preset}}/artifacts/root/filesys/c/ - name: Run Test + if: "${{ matrix.emulator != 'Icicle' || matrix.configuration != 'Debug' || github.event.inputs.icicle_debug == 'true' || github.event.inputs.icicle_debug == 'true' || github.event_name == 'schedule' }}" uses: reactivecircus/android-emulator-runner@v2.34.0 with: api-level: 29 From e749c7d47f894dceeb33d534a3c5bf6f48a630bf Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 7 Apr 2025 09:02:05 +0200 Subject: [PATCH 21/21] Adapt readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b423ea97..669e0c26 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ A high-performance Windows process emulator that operates at syscall level, prov Perfect for security research, malware analysis, and DRM research where fine-grained control over process execution is required. -Built in C++ and powered by the Unicorn Engine. +Built in C++ and powered by the [Unicorn Engine](https://github.com/unicorn-engine/unicorn) (or the [icicle-emu](https://github.com/icicle-emu/icicle-emu) 🆕). ## Key Features