diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e2726cd..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 }} @@ -270,7 +278,7 @@ jobs: - macOS x86_64 emulator: - Unicorn - #- Icicle + - Icicle emulation-root: - Windows 2025 - Windows 2022 @@ -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 @@ -354,7 +363,7 @@ jobs: #- arm64-v8a emulator: - Unicorn - #- Icicle + - Icicle emulation-root: - Windows 2025 - Windows 2022 @@ -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 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 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 39752398..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,49 +53,18 @@ 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_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_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); - } - - 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..2fd10985 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 d6fddef1..8e6aa4b0 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -7,14 +7,16 @@ using icicle_emulator = struct icicle_emulator_; extern "C" { - 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 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; + icicle_emulator* icicle_create_emulator(); int32_t icicle_protect_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions); int32_t icicle_map_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions); @@ -26,9 +28,13 @@ 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_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); - 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 +83,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 @@ -271,18 +262,21 @@ 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(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 = @@ -302,36 +296,66 @@ 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; - } + auto object = make_function_object(std::move(callback)); + auto* ptr = object.get(); + auto* wrapper = +[](void* user, const uint64_t addr) { + const auto& func = *static_cast(user); + (func)(addr); + }; - const auto shared_callback = std::make_shared(std::move(callback)); + const auto id = icicle_add_execution_hook(this->emu_, address, wrapper, ptr); + this->hooks_[id] = std::move(object); - if ((filter & memory_permission::exec) == memory_permission::exec) - { - if (address != 0 || size != std::numeric_limits::max()) - { - throw std::runtime_error("Not supported!"); - } + return wrap_hook(id); + } - 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); - }; + emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override + { + auto object = make_function_object(std::move(callback)); + auto* ptr = object.get(); + auto* wrapper = +[](void* user, const uint64_t addr) { + const 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_generic_execution_hook(this->emu_, wrapper, ptr); + this->hooks_[id] = std::move(object); - return wrap_hook(id); - } + return wrap_hook(id); + } - return nullptr; + emulator_hook* hook_memory_read(const uint64_t address, const size_t size, + memory_access_hook_callback callback) override + { + 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, + memory_access_hook_callback callback) override + { + 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 @@ -343,7 +367,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/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" } 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..26dfefa2 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. @@ -2846,33 +2866,35 @@ 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; } -: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 @@ + + + + + + diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index 292c4fd3..5a25d445 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; @@ -46,8 +46,10 @@ enum HookType { Syscall = 1, Read, Write, - Execute, + ExecuteGeneric, + ExecuteSpecific, Violation, + Interrupt, Unknown, } @@ -123,20 +125,107 @@ 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); } } } +struct ExecutionHooks { + stop: Rc>, + generic_hooks: HookContainer, + specific_hooks: HookContainer, + address_mapping: HashMap>, +} + +impl ExecutionHooks { + pub fn new(stop_value: Rc>) -> Self { + Self { + stop: stop_value, + generic_hooks: HookContainer::new(), + specific_hooks: HookContainer::new(), + address_mapping: HashMap::new(), + } + } + + fn run_hooks(&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 execute(&mut self,cpu: &mut icicle_cpu::Cpu, address: u64) { + self.run_hooks(address); + + if *self.stop.borrow() { + 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) + } + + 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 { + executing_thread: std::thread::ThreadId, vm: icicle_vm::Vm, reg: registers::X64RegisterNodes, syscall_hooks: HookContainer, + interrupt_hooks: HookContainer, violation_hooks: HookContainer bool>, - execution_hooks: Rc>>, + execution_hooks: Rc>, + stop: 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 { @@ -171,23 +260,25 @@ 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 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| { - for (_key, func) in exec_hooks_clone.borrow().get_hooks() { - func(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(), + interrupt_hooks: HookContainer::new(), violation_hooks: HookContainer::new(), execution_hooks: exec_hooks, } @@ -198,12 +289,20 @@ impl IcicleEmulator { } pub fn start(&mut self, count: u64) { + self.executing_thread = std::thread::current().id(); + self.vm.icount_limit = match count { 0 => u64::MAX, - _ => self.vm.cpu.icount + count, + _ => self.vm.cpu.icount.saturating_add(count), }; 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 { @@ -211,14 +310,22 @@ impl IcicleEmulator { icicle_vm::VmExit::UnhandledException((code, value)) => { let continue_execution = self.handle_exception(code, value); if !continue_execution { - break + break; } - }, + } _ => break, }; } } + 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(), @@ -226,8 +333,9 @@ 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), - _ => false + ExceptionCode::InvalidInstruction => self.handle_interrupt(6), + ExceptionCode::DivisionException => self.handle_interrupt(0), + _ => false, }; return continue_execution; @@ -242,13 +350,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,17 +366,26 @@ impl IcicleEmulator { } pub fn stop(&mut self) { - self.vm.icount_limit = 0; + 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 { 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 { @@ -276,13 +393,50 @@ 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, + 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.unwrap(), 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.unwrap(), HookType::Write); + } + pub fn remove_hook(&mut self, id: u32) { let (hook_id, hook_type) = split_hook_id(id); 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::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);()}, + HookType::Write => {self.get_mem().remove_write_hook(hook_id);()}, _ => {} } } @@ -377,7 +531,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)); @@ -389,7 +543,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]; @@ -399,71 +604,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/lib.rs b/src/icicle/src/lib.rs index dab13cfb..19706c0f 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -41,6 +41,8 @@ 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)] pub fn icicle_map_mmio( @@ -164,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 { @@ -181,6 +193,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 { @@ -190,15 +226,23 @@ 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_remove_syscall_hook(ptr: *mut c_void, id: u32) { +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))); + } +} + +#[unsafe(no_mangle)] +pub fn icicle_remove_hook(ptr: *mut c_void, id: u32) { unsafe { let emulator = &mut *(ptr as *mut IcicleEmulator); emulator.remove_hook(id); diff --git a/src/icicle/src/registers.rs b/src/icicle/src/registers.rs index 40d00f9c..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, + fcs: pcode::VarNode, fdp: pcode::VarNode, - //fds: 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,16 +701,33 @@ 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"), - /*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"), + 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,12 +954,10 @@ 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::Fcs => self.fcs, X64Register::Fdp => self.fdp, - //X64Register::Fds => self.fds, + X64Register::Fds => self.fds, X64Register::Fop => self.fop, _ => panic!("Unsupported register"), } diff --git a/src/unicorn-emulator/unicorn_x64_emulator.cpp b/src/unicorn-emulator/unicorn_x64_emulator.cpp index de01afcf..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: @@ -175,63 +176,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{}; @@ -439,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; @@ -537,8 +481,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 +516,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)); @@ -582,38 +525,93 @@ 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(const uint64_t address, const 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(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_operation::read && 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(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 addr, + const int length, const uint64_t value) { + const auto operation = map_memory_operation(type); + if (operation == memory_operation::write && length > 0) + { + c(addr, &value, std::min(static_cast(length), 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"); + } + } };