49 Commits

Author SHA1 Message Date
Duncan Ogilvie e2d2f46a54 Merge pull request #25 from icicle-emu/memory-capacity
Add support for dynamically updating the memory capacity
2025-01-13 20:46:06 +01:00
Duncan Ogilvie e9c03d562f Add support for dynamically updating the memory capacity 2025-01-12 14:09:05 +01:00
Duncan Ogilvie 8acc071b8a Bump rust package to 0.0.10 2024-12-31 00:35:48 +01:00
Duncan Ogilvie 503cf2ce72 Merge pull request #24 from icicle-emu/execute-uninitialized
Add support for execute-only memory and fix some other minor bugs
2024-12-30 03:13:02 +01:00
Duncan Ogilvie 36d4e46246 Update icicle to add support for execute-only code 2024-12-30 03:08:19 +01:00
Duncan Ogilvie 4e32ae3ff5 Add test for executing uninitialized code 2024-12-29 14:16:28 +01:00
Duncan Ogilvie f491a2259a Merge pull request #23 from icicle-emu/push-rewind
Delay updating RSP until after the memory write when executing 'push'
2024-12-28 15:04:46 +01:00
Duncan Ogilvie 37c0fc57a8 Delay updating RSP until after the memory write when executing 'push'
Closes #10
2024-12-28 15:01:03 +01:00
Duncan Ogilvie 412bb928b6 Minor tests cleanup 2024-12-28 15:00:23 +01:00
Duncan Ogilvie 08701ee1f2 Add test for executing uninitialized memory 2024-12-28 14:59:48 +01:00
Duncan Ogilvie 435e9e4df7 Add test for execute-only memory 2024-12-28 14:59:06 +01:00
Duncan Ogilvie 210b64cbb7 Switch to trusted publishing for PyPI 2024-12-28 13:51:39 +01:00
Duncan Ogilvie 0fc786f5f1 Merge pull request #22 from icicle-emu/uninitialized-memory
Map memory as initialized unless `track_uninitialized` is enabled
2024-12-28 10:28:04 +01:00
Duncan Ogilvie 583932dd33 Map memory as initialized unless track_uninitialized is enabled
Related to #9
2024-12-28 10:21:28 +01:00
Duncan Ogilvie ad481a2124 Minor code simplifications 2024-12-28 10:20:22 +01:00
Duncan Ogilvie aef686faa6 Merge pull request #20 from icicle-emu/x86-eflags-hook
X86 eflags hook
2024-12-27 17:15:26 +01:00
Duncan Ogilvie 556eb71fe7 Add custom register handler for eflags on x86
Closes #19
2024-12-27 16:24:51 +01:00
Duncan Ogilvie de16238d15 Add rust test for #19 2024-12-27 16:23:50 +01:00
Duncan Ogilvie 7a095640b4 Downgrade softprops/action-gh-release to v2.0.9
https://github.com/softprops/action-gh-release/issues/555
2024-12-27 15:49:20 +01:00
Duncan Ogilvie 6ad80d947e Bump icicle-emu
https://github.com/icicle-emu/icicle-emu/issues/64
2024-12-25 01:19:23 +01:00
Duncan Ogilvie 3d3b1f7e9a Merge pull request #15 from icicle-emu/ci-bump
CI version bumps
2024-12-25 01:06:52 +01:00
Duncan Ogilvie 91470e40f9 Bump pypa/gh-action-pypi-publish and softprops/action-gh-release 2024-12-25 00:57:31 +01:00
Duncan Ogilvie a703630151 Bump to Python 3.12 for windows and macos
Closes #8
2024-12-25 00:57:07 +01:00
Duncan Ogilvie 829517fcba Merge pull request #11 from icicle-emu/rattle-bug-repros
Add a few tests to reproduce emulator bugs
2024-12-25 00:45:06 +01:00
Duncan Ogilvie 2e4dea36ec Add rust test for #13 2024-12-25 00:41:46 +01:00
Duncan Ogilvie d648e73ba1 Add rust test for #9 2024-12-25 00:41:46 +01:00
Duncan Ogilvie 46a937a0e1 Simplify icicle vm construction in tests 2024-12-25 00:41:46 +01:00
Duncan Ogilvie d8673ecdfd Add rust test for #10 2024-12-25 00:41:46 +01:00
Duncan Ogilvie 38d64a466c Chance icicle initialization parameters 2024-12-25 00:41:46 +01:00
Duncan Ogilvie 5853b82603 Fix test execution by defining GHIDRA_SRC 2024-12-25 00:41:46 +01:00
Duncan Ogilvie 70cfc3260a Switch to a [workspace]
https://github.com/PyO3/pyo3/issues/340
2024-12-25 00:41:46 +01:00
Duncan Ogilvie 1ae0f43fce Move rust tests to a separate crate
https://github.com/PyO3/pyo3/issues/340
2024-12-25 00:41:46 +01:00
Duncan Ogilvie 30b3c7c357 Merge pull request #14 from icicle-emu/write-reg-sp
Fix bug where `reg_write("rip", ...)` would not work after stepping
2024-12-25 00:41:26 +01:00
Duncan Ogilvie a228304530 Add getter/setter for PC and SP registers 2024-12-25 00:38:30 +01:00
Duncan Ogilvie ae409c8f1f Redirect reg_write("rip") to write_pc
Closes #13
2024-12-25 00:38:23 +01:00
Duncan Ogilvie 2f06c21de1 Merge pull request #5 from icicle-emu/minor-improvements
Minor improvements
2024-11-29 23:25:55 +01:00
Duncan Ogilvie 1465ddddaf Bump to 0.0.5 2024-11-29 23:07:14 +01:00
Duncan Ogilvie c4a1c18f04 Bump pyo3 to 0.23.2 2024-11-29 23:06:35 +01:00
Duncan Ogilvie e749fe1571 Disable optimize_block per default 2024-11-29 22:45:03 +01:00
Duncan Ogilvie f8b119ebf2 Add reproduction for block optimization bug 2024-11-29 22:23:14 +01:00
Duncan Ogilvie 5e8b316080 Use Icicle from src/lib in src/main 2024-11-29 22:11:05 +01:00
Duncan Ogilvie f4ef5aa9b2 Bump icicle-emu to the latest version 2024-10-30 00:17:37 +01:00
Duncan Ogilvie a4874322d1 Add Icicle.architecture property 2024-10-13 16:52:09 +02:00
Duncan Ogilvie 4083d9f4d4 Disable shadow stack per default 2024-10-13 16:51:54 +02:00
Duncan Ogilvie d7d49b0c42 Fix deprecated PyO3 functions 2024-10-13 16:51:23 +02:00
Duncan Ogilvie c6ca1f189a Merge pull request #4 from icicle-emu/fix-autocomplete
Fix autocomplete
2024-09-22 22:10:33 +02:00
Duncan Ogilvie 6e5d32f35c Fix GitHub Actions 2024-09-22 22:05:44 +02:00
Duncan Ogilvie cc436bd5fd Bump to 0.0.4 2024-09-22 21:55:59 +02:00
Duncan Ogilvie b376658d59 Move type hints to __init__.py 2024-09-22 21:55:57 +02:00
16 changed files with 2160 additions and 873 deletions
+2
View File
@@ -0,0 +1,2 @@
[env]
GHIDRA_SRC = { value = "python/icicle", relative = true }
+23 -24
View File
@@ -12,14 +12,14 @@ jobs:
PYTHONUNBUFFERED: '1'
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: 'true'
- name: Python environment
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.12'
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
@@ -42,9 +42,9 @@ jobs:
python tests/invalid.py
- name: Upload wheels
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: wheels
name: wheels-windows
path: dist
macos:
@@ -56,14 +56,14 @@ jobs:
PYTHONUNBUFFERED: '1'
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: 'true'
- name: Python environment
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.12'
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
@@ -90,22 +90,22 @@ jobs:
python tests/invalid.py
- name: Upload wheels
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: wheels
name: wheels-macos
path: dist
linux:
# Skip building pull requests from the same repository
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
runs-on: ubuntu-latest
container: quay.io/pypa/manylinux2014_x86_64
runs-on: ubuntu-24.04
container: quay.io/pypa/manylinux_2_28_x86_64
env:
# Disable output buffering in an attempt to get readable errors
PYTHONUNBUFFERED: '1'
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: 'true'
@@ -116,7 +116,7 @@ jobs:
export PATH="$PATH:$HOME/.cargo/bin"
export PATH="/opt/python/cp38-cp38/bin:$PATH"
pip install -r requirements.txt
python setup.py bdist_wheel --py-limited-api=cp37 --plat-name manylinux2014_x86_64
python setup.py bdist_wheel --py-limited-api=cp37 --plat-name manylinux_2_28_x86_64
auditwheel show dist/*.whl
pip install --force-reinstall dist/*.whl
python -c "import icicle"
@@ -129,33 +129,32 @@ jobs:
python tests/invalid.py
- name: Upload wheels
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: wheels
name: wheels-linux
path: dist
release:
if: ${{ startsWith(github.ref, 'refs/tags/') }}
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
needs: [windows, macos, linux]
permissions:
contents: write
discussions: write
id-token: write
steps:
- name: Download wheels
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: wheels
pattern: wheels-*
merge-multiple: true
path: dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@b7f401de30cb6434a1e19f805ff006643653240e # v1.8.10
with:
password: ${{ secrets.PYPI_API_TOKEN }}
packages-dir: dist/
uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.13
- name: Release
uses: softprops/action-gh-release@c9b46fe7aad9f02afd89b12450b780f52dacfb2d # master 2023-03-26
uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.0.9
with:
generate_release_notes: true
files: dist/*
Generated
+203 -251
View File
@@ -1,12 +1,12 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
version = "0.21.0"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"cpp_demangle",
"fallible-iterator",
@@ -15,6 +15,7 @@ dependencies = [
"object",
"rustc-demangle",
"smallvec",
"typed-arena",
]
[[package]]
@@ -30,17 +31,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"getrandom",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "allocator-api2"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]]
name = "anyhow"
version = "1.0.86"
@@ -59,6 +55,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -70,6 +72,9 @@ name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
dependencies = [
"serde",
]
[[package]]
name = "bstr"
@@ -93,12 +98,6 @@ version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -116,31 +115,39 @@ dependencies = [
[[package]]
name = "cranelift"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31bcc3beea0c0bd94c3281ad625ed5a320380078014d15cb046c7bdd563dfb4"
checksum = "27711210499725bafe52c320a988e27283e6cf477ee8edac57e8275bef8ea550"
dependencies = [
"cranelift-codegen",
"cranelift-frontend",
"cranelift-module",
]
[[package]]
name = "cranelift-bforest"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebf72ceaf38f7d41194d0cf6748214d8ef7389167fe09aad80f87646dbfa325b"
checksum = "540b193ff98b825a1f250a75b3118911af918a734154c69d80bcfcf91e7e9522"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.107.2"
name = "cranelift-bitset"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ee7fde5cd9173f00ce02c491ee9e306d64740f4b1a697946e0474f389999e13"
checksum = "c7cb269598b9557ab942d687d3c1086d77c4b50dcf35813f3a65ba306fd42279"
[[package]]
name = "cranelift-codegen"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46566d7c83a8bff4150748d66020f4c7224091952aa4b4df1ec4959c39d937a1"
dependencies = [
"bumpalo",
"cranelift-bforest",
"cranelift-bitset",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"cranelift-control",
@@ -150,45 +157,49 @@ dependencies = [
"hashbrown 0.14.5",
"log",
"regalloc2",
"rustc-hash",
"smallvec",
"target-lexicon",
]
[[package]]
name = "cranelift-codegen-meta"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b49bec6a517e78d4067500dc16acb558e772491a2bcb37301127448adfb8413c"
checksum = "2df8a86a34236cc75a8a6a271973da779c2aeb36c43b6e14da474cf931317082"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ead4ea497b2dc2ac31fcabd6d5d0d5dc25b3964814122e343724bdf65a53c843"
checksum = "cf75340b6a57b7c7c1b74f10d3d90883ee6d43a554be8131a4046c2ebcf5eb65"
[[package]]
name = "cranelift-control"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81e8028c8d711ea7592648e70221f2e54acb8665f7ecd49545f021ec14c3341"
checksum = "2e84495bc5d23d86aad8c86f8ade4af765b94882af60d60e271d3153942f1978"
dependencies = [
"arbitrary",
]
[[package]]
name = "cranelift-entity"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32acd0632ba65c2566e75f64af9ef094bb8d90e58a9fbd33d920977a9d85c054"
checksum = "963c17147b80df351965e57c04d20dbedc85bcaf44c3436780a59a3f1ff1b1c2"
dependencies = [
"cranelift-bitset",
]
[[package]]
name = "cranelift-frontend"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a395a704934aa944ba8939cac9001174b9ae5236f48bc091f89e33bb968336f6"
checksum = "727f02acbc4b4cb2ba38a6637101d579db50190df1dd05168c68e762851a3dd5"
dependencies = [
"cranelift-codegen",
"log",
@@ -198,15 +209,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b325ce81c4ee7082dc894537eb342c37898e14230fe7c02ea945691db3e2dd01"
checksum = "32b00cc2e03c748f2531eea01c871f502b909d30295fdcad43aec7bf5c5b4667"
[[package]]
name = "cranelift-jit"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5840f54fc4b65854222339c834f3e01c329488cd12901c0dda8f69f82df6dcb2"
checksum = "f74630af581f32b99c8f4e06ee45799383ecc0795e3ff8aa86b7584bb2d643fd"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -219,14 +230,14 @@ dependencies = [
"region",
"target-lexicon",
"wasmtime-jit-icache-coherence",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
name = "cranelift-module"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a86ed143dc1ba89a513fa8d9fb443c3e36fa9a2e5f64d7431765ea8f9e6f5c1"
checksum = "6aaa16c4f18a15be310df221ea544f516acc42fc58ca96e09a3d08651744efa1"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -235,9 +246,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
version = "0.107.2"
version = "0.113.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea11f5ac85996fa093075d66397922d4f56085d5d84ec13043d0cd4f159c6818"
checksum = "bbeaf978dc7c1a2de8bbb9162510ed218eb156697bc45590b8fbdd69bb08e8de"
dependencies = [
"cranelift-codegen",
"libc",
@@ -259,17 +270,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "derive_more"
version = "0.99.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@@ -303,10 +303,27 @@ dependencies = [
]
[[package]]
name = "gimli"
version = "0.28.1"
name = "foldhash"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
dependencies = [
"fallible-iterator",
"indexmap",
@@ -325,38 +342,39 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.13.2"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
dependencies = [
"ahash",
"allocator-api2",
"foldhash",
]
[[package]]
name = "heck"
version = "0.4.1"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "icicle-cpu"
version = "0.1.0"
dependencies = [
"addr2line",
"ahash",
"anyhow",
"bitflags 2.5.0",
"bytemuck",
"gimli",
"half",
"hashbrown 0.14.5",
"icicle-mem",
"object",
"pcode",
@@ -406,7 +424,7 @@ dependencies = [
[[package]]
name = "icicle-python"
version = "0.0.3"
version = "0.0.10"
dependencies = [
"icicle-cpu",
"icicle-vm",
@@ -428,8 +446,10 @@ dependencies = [
"icicle-cpu",
"icicle-jit",
"icicle-linux",
"ihex",
"object",
"pcode",
"ron",
"serde",
"serde-xml-rs",
"sleigh-compile",
@@ -439,13 +459,19 @@ dependencies = [
]
[[package]]
name = "indexmap"
version = "2.2.6"
name = "ihex"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
checksum = "365a784774bb381e8c19edb91190a90d7f2625e057b55de2bc0f6b57bc779ff2"
[[package]]
name = "indexmap"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
"hashbrown 0.14.5",
"hashbrown 0.15.0",
]
[[package]]
@@ -472,16 +498,6 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.17"
@@ -492,10 +508,10 @@ dependencies = [
]
[[package]]
name = "mach"
version = "0.3.2"
name = "mach2"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
dependencies = [
"libc",
]
@@ -508,9 +524,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memmap2"
version = "0.5.10"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
dependencies = [
"libc",
]
@@ -545,13 +561,13 @@ dependencies = [
[[package]]
name = "object"
version = "0.32.2"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
dependencies = [
"crc32fast",
"flate2",
"hashbrown 0.14.5",
"hashbrown 0.15.0",
"indexmap",
"memchr",
"ruzstd",
@@ -569,29 +585,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys 0.45.0",
]
[[package]]
name = "pcode"
version = "0.2.0"
@@ -619,16 +612,16 @@ dependencies = [
[[package]]
name = "pyo3"
version = "0.21.2"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8"
checksum = "e484fd2c8b4cb67ab05a318f1fd6fa8f199fcc30819f08f07d200809dba26c15"
dependencies = [
"cfg-if",
"indexmap",
"indoc",
"libc",
"memoffset",
"parking_lot",
"once_cell",
"portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
@@ -638,9 +631,9 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
version = "0.21.2"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50"
checksum = "dc0e0469a84f208e20044b98965e1561028180219e35352a2afaf2b942beff3b"
dependencies = [
"once_cell",
"target-lexicon",
@@ -648,9 +641,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
version = "0.21.2"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403"
checksum = "eb1547a7f9966f6f1a0f0227564a9945fe36b90da5a93b3933fc3dc03fae372d"
dependencies = [
"libc",
"pyo3-build-config",
@@ -658,9 +651,9 @@ dependencies = [
[[package]]
name = "pyo3-macros"
version = "0.21.2"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c"
checksum = "fdb6da8ec6fa5cedd1626c886fc8749bdcbb09424a86461eb8cdf096b7c33257"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
@@ -670,9 +663,9 @@ dependencies = [
[[package]]
name = "pyo3-macros-backend"
version = "0.21.2"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c"
checksum = "38a385202ff5a92791168b1136afae5059d3ac118457bb7bc304c197c2d33e7d"
dependencies = [
"heck",
"proc-macro2",
@@ -690,22 +683,13 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "regalloc2"
version = "0.9.3"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6"
checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0"
dependencies = [
"hashbrown 0.13.2",
"hashbrown 0.14.5",
"log",
"rustc-hash",
"slice-group-by",
@@ -714,14 +698,26 @@ dependencies = [
[[package]]
name = "region"
version = "2.2.0"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7"
dependencies = [
"bitflags 1.3.2",
"libc",
"mach",
"winapi",
"mach2",
"windows-sys 0.52.0",
]
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64",
"bitflags 2.5.0",
"serde",
"serde_derive",
]
[[package]]
@@ -732,9 +728,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]]
name = "rustix"
@@ -751,21 +747,13 @@ dependencies = [
[[package]]
name = "ruzstd"
version = "0.5.0"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d"
checksum = "99c3938e133aac070997ddc684d4b393777d293ba170f2988c8fd5ea2ad4ce21"
dependencies = [
"byteorder",
"derive_more",
"twox-hash",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.203"
@@ -868,9 +856,17 @@ dependencies = [
[[package]]
name = "target-lexicon"
version = "0.12.14"
version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tests"
version = "0.0.0"
dependencies = [
"icicle-python",
"pyo3",
]
[[package]]
name = "thiserror"
@@ -969,6 +965,12 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "typed-arena"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]]
name = "unicode-ident"
version = "1.0.9"
@@ -994,10 +996,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasmtime-jit-debug"
version = "19.0.2"
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92de34217bf7f0464262adf391a9950eba440f9dfc7d3b0e3209302875c6f65f"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasmtime-jit-debug"
version = "26.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f02a0118d471de665565ed200bc56673eaa10cc8e223dfe2cef5d50ed0d9d143"
dependencies = [
"object",
"rustix",
@@ -1006,20 +1014,21 @@ dependencies = [
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "20.0.2"
version = "26.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede45379f3b4d395d8947006de8043801806099a240a26db553919b68e96ab15"
checksum = "da47fba49af72581bc0dc67c8faaf5ee550e6f106e285122a184a675193701a5"
dependencies = [
"anyhow",
"cfg-if",
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
name = "wasmtime-versioned-export-macros"
version = "19.0.2"
version = "26.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffaafa5c12355b1a9ee068e9295d50c4ca0a400c721950cdae4f5b54391a2da5"
checksum = "db8efb877c9e5e67239d4553bb44dd2a34ae5cfb728f3cf2c5e64439c6ca6ee7"
dependencies = [
"proc-macro2",
"quote",
@@ -1048,144 +1057,87 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.5",
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm 0.52.5",
"windows_aarch64_msvc 0.52.5",
"windows_i686_gnu 0.52.5",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.5",
"windows_x86_64_gnu 0.52.5",
"windows_x86_64_gnullvm 0.52.5",
"windows_x86_64_msvc 0.52.5",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "xml-rs"
+15 -5
View File
@@ -1,24 +1,34 @@
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
members = ["tests"]
exclude = ["icicle-emu"]
[package]
name = "icicle-python"
version = "0.0.3"
version = "0.0.10"
edition = "2021"
[lib]
name = "icicle"
crate-type = ["cdylib"]
crate-type = ["cdylib", "lib"]
[workspace.dependencies]
pyo3 = { version = "0.23.3", features = ["indexmap", "abi3-py37"] }
[dependencies]
pyo3 = { workspace = true }
icicle-cpu = { path = "icicle-emu/icicle-cpu" }
icicle-vm = { path = "icicle-emu/icicle-vm" }
pcode = { path = "icicle-emu/sleigh/pcode" }
sleigh-runtime = { path = "icicle-emu/sleigh/sleigh-runtime" }
indexmap = "2.2.6"
pyo3 = { version = "0.21.2", features = ["extension-module", "indexmap", "abi3-py37"] }
target-lexicon = "0.12.7"
tracing = "*"
tracing-subscriber = "0.3.17"
[build-dependencies]
pyo3-build-config = "0.21.2"
pyo3-build-config = "0.23.3"
# Reference: https://github.com/PyO3/pyo3/issues/340
[features]
extension-module = ["pyo3/extension-module"]
default = ["extension-module"]
@@ -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
+151 -2
View File
@@ -1,4 +1,150 @@
from .icicle import *
from typing import List, Dict, Tuple
from enum import Enum
class MemoryProtection(Enum):
NoAccess = ...
ReadOnly = ...
ReadWrite = ...
ExecuteOnly = ...
ExecuteRead = ...
ExecuteReadWrite = ...
class MemoryExceptionCode(Enum):
Unallocated = ...
Unmapped = ...
UnmappedRegisters = ...
Uninitialized = ...
ReadViolation = ...
WriteViolation = ...
ExecViolation = ...
ReadWatch = ...
WriteWatch = ...
Unaligned = ...
OutOfMemory = ...
SelfModifyingCode = ...
AddressOverflow = ...
Unknown = ...
class RunStatus(Enum):
Running = ...
InstructionLimit = ...
Breakpoint = ...
Interrupted = ...
Halt = ...
Killed = ...
Deadlock = ...
OutOfMemory = ...
Unimplemented = ...
UnhandledException = ...
class ExceptionCode(Enum):
NoException = ...
InstructionLimit = ...
Halt = ...
Sleep = ...
Syscall = ...
CpuStateChanged = ...
DivisionException = ...
ReadUnmapped = ...
ReadPerm = ...
ReadUnaligned = ...
ReadWatch = ...
ReadUninitialized = ...
WriteUnmapped = ...
WritePerm = ...
WriteWatch = ...
WriteUnaligned = ...
ExecViolation = ...
SelfModifyingCode = ...
OutOfMemory = ...
AddressOverflow = ...
InvalidInstruction = ...
UnknownInterrupt = ...
UnknownCpuID = ...
InvalidOpSize = ...
InvalidFloatSize = ...
CodeNotTranslated = ...
ShadowStackOverflow = ...
ShadowStackInvalid = ...
InvalidTarget = ...
UnimplementedOp = ...
ExternalAddr = ...
Environment = ...
JitError = ...
InternalError = ...
UnmappedRegister = ...
UnknownError = ...
class Icicle:
def __init__(self, architecture: str, *,
jit = True,
jit_mem = True,
shadow_stack = False,
recompilation = True,
track_uninitialized = False,
optimize_instructions = True,
optimize_block = False,
tracing = False,
) -> None: ...
@property
def architecture(self) -> str: ...
@property
def exception_code(self) -> ExceptionCode: ...
@property
def exception_value(self) -> int: ...
icount: int
icount_limit: int
pc: int
sp: int
"""
Physical memory capacity in pages (adjust when seeing OutOfMemory)
The default limit is set so that the maximum corresponds to ~400 MB of host memory.
"""
mem_capacity: int
# TODO: API to get memory information?
def mem_map(self, address: int, size: int, protection: MemoryProtection): ...
def mem_unmap(self, address: int, size: int): ...
def mem_protect(self, address: int, size: int, protection: MemoryProtection): ...
def mem_read(self, address: int, size: int) -> bytes: ...
def mem_write(self, address: int, data: bytes) -> None: ...
def reg_list(self) -> Dict[str, Tuple[int, int]]: ...
def reg_offset(self, name: str) -> int: ...
def reg_size(self, name: str) -> int: ...
def reg_read(self, name: str) -> int: ...
def reg_write(self, name: str, value: int) -> None: ...
def reset(self): ...
def run(self) -> RunStatus: ...
def run_until(self, address: int) -> RunStatus: ...
def step(self, count: int) -> RunStatus: ...
def add_breakpoint(self, address: int) -> bool: ...
def remove_breakpoint(self, address: int) -> bool: ...
def architectures() -> List[str]: ...
class MemoryException(Exception):
def __init__(self, message: str, code: MemoryExceptionCode):
@@ -6,7 +152,7 @@ class MemoryException(Exception):
self.code = code
def __str__(self):
return f"{super().__str__()}: {self.code}"
return f"{super().__str__()} ({self.code})"
def __ghidra_init():
import os
@@ -19,3 +165,6 @@ def __ghidra_init():
raise FileNotFoundError("Ghidra processor definitions not found")
__ghidra_init()
# NOTE: This overrides the stubs at runtime with the actual implementation
from .icicle import *
-134
View File
@@ -1,134 +0,0 @@
from typing import List, Dict, Tuple
from enum import Enum
class MemoryProtection(Enum):
NoAccess = ...
ReadOnly = ...
ReadWrite = ...
ExecuteOnly = ...
ExecuteRead = ...
ExecuteReadWrite = ...
class MemoryExceptionCode(Enum):
Unallocated = ...
Unmapped = ...
UnmappedRegisters = ...
Uninitialized = ...
ReadViolation = ...
WriteViolation = ...
ExecViolation = ...
ReadWatch = ...
WriteWatch = ...
Unaligned = ...
OutOfMemory = ...
SelfModifyingCode = ...
AddressOverflow = ...
Unknown = ...
class RunStatus(Enum):
Running = ...
InstructionLimit = ...
Breakpoint = ...
Interrupted = ...
Halt = ...
Killed = ...
Deadlock = ...
OutOfMemory = ...
Unimplemented = ...
UnhandledException = ...
class ExceptionCode(Enum):
NoException = ...
InstructionLimit = ...
Halt = ...
Sleep = ...
Syscall = ...
CpuStateChanged = ...
DivisionException = ...
ReadUnmapped = ...
ReadPerm = ...
ReadUnaligned = ...
ReadWatch = ...
ReadUninitialized = ...
WriteUnmapped = ...
WritePerm = ...
WriteWatch = ...
WriteUnaligned = ...
ExecViolation = ...
SelfModifyingCode = ...
OutOfMemory = ...
AddressOverflow = ...
InvalidInstruction = ...
UnknownInterrupt = ...
UnknownCpuID = ...
InvalidOpSize = ...
InvalidFloatSize = ...
CodeNotTranslated = ...
ShadowStackOverflow = ...
ShadowStackInvalid = ...
InvalidTarget = ...
UnimplementedOp = ...
ExternalAddr = ...
Environment = ...
JitError = ...
InternalError = ...
UnmappedRegister = ...
UnknownError = ...
class Icicle:
def __init__(self, architecture: str, *,
jit = True,
jit_mem = True,
shadow_stack = True,
recompilation = True,
track_uninitialized = False,
optimize_instructions = True,
optimize_block = True,
tracing = False,
) -> None: ...
@property
def exception_code(self) -> ExceptionCode: ...
@property
def exception_value(self) -> int: ...
icount: int
icount_limit: int
# TODO: API to get memory information?
def mem_map(self, address: int, size: int, protection: MemoryProtection): ...
def mem_unmap(self, address: int, size: int): ...
def mem_protect(self, address: int, size: int, protection: MemoryProtection): ...
def mem_read(self, address: int, size: int) -> bytes: ...
def mem_write(self, address: int, data: bytes) -> None: ...
def reg_list(self) -> Dict[str, Tuple[int, int]]: ...
def reg_offset(self, name: str) -> int: ...
def reg_size(self, name: str) -> int: ...
def reg_read(self, name: str) -> int: ...
def reg_write(self, name: str, value: int) -> None: ...
def reset(self): ...
def run(self) -> RunStatus: ...
def run_until(self, address: int) -> RunStatus: ...
def step(self, count: int) -> RunStatus: ...
def add_breakpoint(self, address: int) -> bool: ...
def remove_breakpoint(self, address: int) -> bool: ...
def architectures() -> List[str]: ...
View File
+132 -53
View File
@@ -1,22 +1,38 @@
use std::borrow::Cow;
use std::collections::HashMap;
use icicle_cpu::mem::{Mapping, MemError, perm};
use icicle_cpu::{ExceptionCode, VmExit};
use icicle_cpu::{Cpu, ExceptionCode, ValueSource, VmExit};
use pyo3::prelude::*;
use icicle_vm;
use icicle_vm::linux::LinuxCpu;
use pyo3::exceptions::*;
use target_lexicon;
use indexmap::IndexMap;
use target_lexicon::Architecture;
use sleigh_runtime::NamedRegister;
// References:
// - https://pyo3.rs/main/conversions/tables
// - https://pyo3.rs/main/class
#[pyclass(module = "icicle")]
#[derive(Clone)]
enum MemoryProtection {
struct X86FlagsRegHandler {
pub eflags: pcode::VarNode,
}
impl icicle_cpu::RegHandler for X86FlagsRegHandler {
fn read(&mut self, cpu: &mut Cpu) {
let eflags = icicle_vm::x86::eflags(cpu);
cpu.write_var::<u32>(self.eflags, eflags);
}
fn write(&mut self, cpu: &mut Cpu) {
let eflags = cpu.read_var::<u32>(self.eflags);
icicle_vm::x86::set_eflags(cpu, eflags);
}
}
#[pyclass(eq, eq_int, module = "icicle")]
#[derive(Clone, Debug, PartialEq)]
pub enum MemoryProtection {
NoAccess,
ReadOnly,
ReadWrite,
@@ -25,9 +41,9 @@ enum MemoryProtection {
ExecuteReadWrite,
}
#[pyclass(module = "icicle")]
#[derive(Clone)]
enum RunStatus {
#[pyclass(eq, eq_int, module = "icicle")]
#[derive(Clone, Debug, PartialEq)]
pub enum RunStatus {
/// The VM is still running.
Running,
@@ -59,8 +75,9 @@ enum RunStatus {
UnhandledException,
}
#[pyclass(module = "icicle")]
enum MemoryExceptionCode {
#[pyclass(eq, eq_int, module = "icicle")]
#[derive(Clone, Debug, PartialEq)]
pub enum MemoryExceptionCode {
Unallocated,
Unmapped,
UnmappedRegister,
@@ -98,9 +115,9 @@ impl From<MemError> for MemoryExceptionCode {
}
}
#[pyclass(module = "icicle", name = "ExceptionCode")]
#[derive(Clone)]
enum ExceptionCodePy {
#[pyclass(eq, eq_int, module = "icicle", name = "ExceptionCode")]
#[derive(Clone, Debug, PartialEq)]
pub enum ExceptionCodePy {
NoException = 0x0000,
InstructionLimit = 0x0001,
@@ -219,13 +236,14 @@ fn convert_protection(protection: MemoryProtection) -> u8 {
}
#[pyclass(unsendable, module = "icicle")]
struct Icicle {
pub struct Icicle {
architecture: String,
vm: icicle_vm::Vm,
regs: HashMap<String, NamedRegister>,
}
fn reg_find<'a>(i: &'a Icicle, name: &str) -> PyResult<&'a NamedRegister> {
let sleigh = i.vm.cpu.sleigh();
let sleigh = &i.vm.cpu.arch.sleigh;
match sleigh.get_reg(name) {
None => {
i.regs.get(name.to_lowercase().as_str())
@@ -240,48 +258,91 @@ fn reg_find<'a>(i: &'a Icicle, name: &str) -> PyResult<&'a NamedRegister> {
#[pymethods]
impl Icicle {
#[getter]
fn get_icount_limit(&mut self) -> u64 {
pub fn get_icount_limit(&mut self) -> u64 {
self.vm.icount_limit
}
#[setter]
fn set_icount_limit(&mut self, value: u64) {
pub fn set_icount_limit(&mut self, value: u64) {
self.vm.icount_limit = value;
}
#[getter]
fn get_icount(&mut self) -> u64 {
return self.vm.cpu.icount;
pub fn get_icount(&mut self) -> u64 {
self.vm.cpu.icount
}
#[setter]
fn set_icount(&mut self, value: u64) {
pub fn set_icount(&mut self, value: u64) {
self.vm.cpu.icount = value;
}
#[getter]
fn get_exception_code(&self) -> ExceptionCodePy {
pub fn get_exception_code(&self) -> ExceptionCodePy {
ExceptionCode::from_u32(self.vm.cpu.exception.code).into()
}
#[getter]
fn get_exception_value(&self) -> u64 {
pub fn get_exception_value(&self) -> u64 {
self.vm.cpu.exception.value
}
#[getter]
pub fn get_architecture(&self) -> String {
self.architecture.to_string()
}
#[getter]
pub fn get_pc(&self) -> u64 {
self.vm.cpu.read_pc()
}
#[setter]
pub fn set_pc(&mut self, address: u64) {
self.vm.cpu.write_pc(address)
}
#[getter]
pub fn get_sp(&mut self) -> u64 {
self.vm.cpu.read_reg(self.vm.cpu.arch.reg_sp)
}
#[setter]
pub fn set_sp(&mut self, address: u64) {
self.vm.cpu.write_reg(self.vm.cpu.arch.reg_sp, address)
}
#[getter]
pub fn get_mem_capacity(&self) -> usize {
self.vm.cpu.mem.capacity()
}
#[setter]
pub fn set_mem_capacity(&mut self, capacity: usize) -> PyResult<()> {
if self.vm.cpu.mem.set_capacity(capacity) {
return Ok(());
}
Err(
raise_MemoryException(
format!("Reducing memory capacity is not supported"),
MemError::Unknown,
)
)
}
#[new]
#[pyo3(signature = (
architecture,
jit = true,
jit_mem = true,
shadow_stack = true,
shadow_stack = false,
recompilation = true,
track_uninitialized = false,
optimize_instructions = true,
optimize_block = true,
optimize_block = false,
tracing = false,
))]
fn new(
pub fn new(
architecture: String,
jit: bool,
jit_mem: bool,
@@ -308,7 +369,7 @@ impl Icicle {
}
}
// Setup the CPU state for the target triple
// Set up the CPU state for the target triple
let mut config = icicle_vm::cpu::Config::from_target_triple(
format!("{architecture}-none").as_str()
);
@@ -327,38 +388,50 @@ impl Icicle {
config.optimize_instructions = optimize_instructions;
config.optimize_block = optimize_block;
let vm = icicle_vm::build(&config)
let mut vm = icicle_vm::build(&config)
.map_err(|e| {
PyException::new_err(format!("VM build error: {e}"))
})?;
// Populate the lowercase register map
let mut regs = HashMap::new();
let sleigh = vm.cpu.sleigh();
let sleigh = &vm.cpu.arch.sleigh;
for reg in &sleigh.named_registers {
let name = sleigh.get_str(reg.name);
regs.insert(name.to_lowercase(), reg.clone());
}
// Special handling for x86 flags
match config.triple.architecture {
Architecture::X86_32(_) | Architecture::X86_64 | Architecture::X86_64h => {
let eflags = sleigh.get_reg("eflags").unwrap().var;
let reg_handler = X86FlagsRegHandler { eflags };
vm.cpu.add_reg_handler(eflags.id, Box::new(reg_handler));
}
_ => {}
}
Ok(Icicle {
architecture,
vm,
regs,
})
}
fn __str__(&mut self) -> String {
pub fn __str__(&mut self) -> String {
let arch = &self.vm.cpu.arch;
let endianness = if arch.sleigh.big_endian {
"big endian"
} else {
"little endian"
};
format!("Icicle VM for {0:?} ({endianness})", arch.triple.architecture)
format!("Icicle VM for {0:?} ({endianness})", self.architecture)
}
fn mem_map(&mut self, address: u64, size: u64, protection: MemoryProtection) -> PyResult<()> {
pub fn mem_map(&mut self, address: u64, size: u64, protection: MemoryProtection) -> PyResult<()> {
let init_perm = if self.vm.cpu.mem.track_uninitialized { perm::NONE } else { perm::INIT };
let mapping = Mapping {
perm: convert_protection(protection),
perm: convert_protection(protection) | init_perm,
value: 0,
};
if self.vm.cpu.mem.map_memory_len(address, size, mapping) {
@@ -373,7 +446,7 @@ impl Icicle {
}
}
fn mem_unmap(&mut self, address: u64, size: u64) -> PyResult<()> {
pub fn mem_unmap(&mut self, address: u64, size: u64) -> PyResult<()> {
if self.vm.cpu.mem.unmap_memory_len(address, size) {
Ok(())
} else {
@@ -386,7 +459,7 @@ impl Icicle {
}
}
fn mem_protect(&mut self, address: u64, size: usize, protection: MemoryProtection) -> PyResult<()> {
pub fn mem_protect(&mut self, address: u64, size: usize, protection: MemoryProtection) -> PyResult<()> {
self.vm.cpu.mem.update_perm(address, size as u64, convert_protection(protection))
.map_err(|e| {
raise_MemoryException(
@@ -397,7 +470,7 @@ impl Icicle {
Ok(())
}
fn mem_read(&mut self, address: u64, size: usize) -> PyResult<Cow<[u8]>> {
pub fn mem_read(&mut self, address: u64, size: usize) -> PyResult<Cow<[u8]>> {
// Allocate a buffer
let mut buffer = Vec::with_capacity(size);
buffer.resize(size, 0);
@@ -410,10 +483,10 @@ impl Icicle {
e,
)
})?;
return Ok(Cow::Owned(buffer));
Ok(Cow::Owned(buffer))
}
fn mem_write(&mut self, address: u64, data: Vec<u8>) -> PyResult<()> {
pub fn mem_write(&mut self, address: u64, data: Vec<u8>) -> PyResult<()> {
let size = data.len();
self.vm.cpu.mem.write_bytes(address, &data[..], perm::NONE)
.map_err(|e| {
@@ -424,37 +497,43 @@ impl Icicle {
})
}
fn reg_list(&self) -> PyResult<IndexMap<String, (u32, u8)>> {
pub fn reg_list(&self) -> PyResult<IndexMap<String, (u32, u8)>> {
let mut result = IndexMap::new();
let sleigh = self.vm.cpu.sleigh();
let sleigh = &self.vm.cpu.arch.sleigh;
for reg in &sleigh.named_registers {
let name = sleigh.get_str(reg.name);
result.insert(name.to_string(), (reg.offset, reg.var.size));
}
return Ok(result);
Ok(result)
}
fn reg_offset(&self, name: &str) -> PyResult<u32> {
pub fn reg_offset(&self, name: &str) -> PyResult<u32> {
Ok(reg_find(self, name)?.offset)
}
fn reg_size(&self, name: &str) -> PyResult<u8> {
pub fn reg_size(&self, name: &str) -> PyResult<u8> {
Ok(reg_find(self, name)?.var.size)
}
fn reg_read(&mut self, name: &str) -> PyResult<u64> {
pub fn reg_read(&mut self, name: &str) -> PyResult<u64> {
Ok(self.vm.cpu.read_reg(reg_find(self, name)?.var))
}
fn reg_write(&mut self, name: &str, value: u64) -> PyResult<()> {
Ok(self.vm.cpu.write_reg(reg_find(self, name)?.var, value))
pub fn reg_write(&mut self, name: &str, value: u64) -> PyResult<()> {
let var = reg_find(self, name)?.var;
if var == self.vm.cpu.arch.reg_pc {
self.vm.cpu.write_pc(value);
} else {
self.vm.cpu.write_reg(var, value);
}
Ok(())
}
fn reset(&mut self) {
pub fn reset(&mut self) {
self.vm.reset();
}
fn run(&mut self) -> RunStatus {
pub fn run(&mut self) -> RunStatus {
match self.vm.run() {
VmExit::Running => RunStatus::Running,
VmExit::InstructionLimit => RunStatus::InstructionLimit,
@@ -469,7 +548,7 @@ impl Icicle {
}
}
fn run_until(&mut self, address: u64) -> RunStatus {
pub fn run_until(&mut self, address: u64) -> RunStatus {
let breakpoint_added = self.vm.add_breakpoint(address);
let status = self.run();
if breakpoint_added {
@@ -478,7 +557,7 @@ impl Icicle {
status
}
fn step(&mut self, count: u64) -> RunStatus {
pub fn step(&mut self, count: u64) -> RunStatus {
let old_limit = self.vm.icount_limit;
self.vm.icount_limit = self.vm.cpu.icount.saturating_add(count);
let status = self.run();
@@ -486,17 +565,17 @@ impl Icicle {
status
}
fn add_breakpoint(&mut self, address: u64) -> bool {
pub fn add_breakpoint(&mut self, address: u64) -> bool {
self.vm.add_breakpoint(address)
}
fn remove_breakpoint(&mut self, address: u64) -> bool {
pub fn remove_breakpoint(&mut self, address: u64) -> bool {
self.vm.remove_breakpoint(address)
}
}
#[pyfunction]
fn architectures() -> PyResult<Vec<&'static str>> {
pub fn architectures() -> PyResult<Vec<&'static str>> {
Ok(vec![
"i686",
"x86_64",
@@ -508,7 +587,7 @@ fn architectures() -> PyResult<Vec<&'static str>> {
/// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to
/// import the module.
#[pymodule]
fn icicle(_: Python<'_>, m: &PyModule) -> PyResult<()> {
fn icicle(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(architectures, m)?)?;
m.add_class::<Icicle>()?;
m.add_class::<MemoryProtection>()?;
-379
View File
@@ -1,379 +0,0 @@
use std::borrow::Cow;
use std::collections::HashMap;
use icicle_cpu::mem::{Mapping, perm};
use icicle_cpu::{VmExit};
use icicle_vm;
use icicle_vm::linux::LinuxCpu;
use target_lexicon;
use indexmap::IndexMap;
use sleigh_runtime::NamedRegister;
#[allow(dead_code)]
#[derive(Clone)]
enum MemoryProtection {
NoAccess,
ReadOnly,
ReadWrite,
ExecuteOnly,
ExecuteRead,
ExecuteReadWrite,
}
struct Icicle {
vm: icicle_vm::Vm,
regs: HashMap<String, NamedRegister>,
}
fn convert_protection(protection: MemoryProtection) -> u8 {
match protection {
MemoryProtection::NoAccess => perm::NONE,
MemoryProtection::ReadOnly => perm::READ,
MemoryProtection::ReadWrite => perm::READ | perm::WRITE,
MemoryProtection::ExecuteOnly => perm::EXEC,
MemoryProtection::ExecuteRead => perm::EXEC | perm::READ,
MemoryProtection::ExecuteReadWrite => perm::EXEC | perm::READ | perm::WRITE,
}
}
fn reg_find<'a>(i: &'a Icicle, name: &str) -> Result<&'a NamedRegister, String> {
let sleigh = i.vm.cpu.sleigh();
match sleigh.get_reg(name) {
None => {
i.regs.get(name.to_lowercase().as_str())
.ok_or(
format!("Register not found: {name}")
)
}
Some(r) => Ok(r),
}
}
impl Icicle {
#[allow(dead_code)]
fn get_icount_limit(&mut self) -> u64 {
self.vm.icount_limit
}
#[allow(dead_code)]
fn set_icount_limit(&mut self, value: u64) {
self.vm.icount_limit = value;
}
#[allow(dead_code)]
fn get_icount(&mut self) -> u64 {
return self.vm.cpu.icount;
}
#[allow(dead_code)]
fn set_icount(&mut self, value: u64) {
self.vm.cpu.icount = value;
}
fn new(
architecture: String,
jit: bool,
jit_mem: bool,
shadow_stack: bool,
recompilation: bool,
track_uninitialized: bool,
optimize_instructions: bool,
optimize_block: bool,
tracing: bool,
) -> Result<Self, String> {
// Prevent mixing '_' and '-'
if architecture.split("-").count() != 1 {
return Err(
format!("Bad architecture format: {architecture}")
);
}
// TODO: support instantiating this multiple times
if tracing {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.with_target(false)
.init();
}
// Setup the CPU state for the target triple
let mut config = icicle_vm::cpu::Config::from_target_triple(
format!("{architecture}-none").as_str()
);
if config.triple.architecture == target_lexicon::Architecture::Unknown {
return Err(
format!("Unknown architecture: {architecture}")
);
}
// Configuration
config.enable_jit = jit;
config.enable_jit_mem = jit_mem;
config.enable_shadow_stack = shadow_stack;
config.enable_recompilation = recompilation;
config.track_uninitialized = track_uninitialized;
config.optimize_instructions = optimize_instructions;
config.optimize_block = optimize_block;
let vm = icicle_vm::build(&config)
.map_err(|e| {
format!("VM build error: {e}")
})?;
// Populate the lowercase register map
let mut regs = HashMap::new();
let sleigh = vm.cpu.sleigh();
for reg in &sleigh.named_registers {
let name = sleigh.get_str(reg.name);
regs.insert(name.to_lowercase(), reg.clone());
}
Ok(Icicle {
vm,
regs,
})
}
fn __str__(&mut self) -> String {
let arch = &self.vm.cpu.arch;
let endianness = if arch.sleigh.big_endian {
"big endian"
} else {
"little endian"
};
format!("Icicle VM for {0:?} ({endianness})", arch.triple.architecture)
}
fn mem_map(&mut self, address: u64, size: u64, protection: MemoryProtection) -> Result<(), String> {
let mapping = Mapping {
perm: convert_protection(protection),
value: 0,
};
if self.vm.cpu.mem.map_memory_len(address, size, mapping) {
Ok(())
} else {
Err(
format!("Failed to map memory {address:X}[{size:X}]")
)
}
}
#[allow(dead_code)]
fn mem_unmap(&mut self, address: u64, size: u64) -> Result<(), String> {
if self.vm.cpu.mem.unmap_memory_len(address, size) {
Ok(())
} else {
Err(
format!("Failed to unmap memory {address:X}[{size:X}]")
)
}
}
fn mem_protect(&mut self, address: u64, size: usize, protection: MemoryProtection) -> Result<(), String> {
self.vm.cpu.mem.update_perm(address, size as u64, convert_protection(protection))
.map_err(|_| {
format!("Failed to protect memory {address:X}[{size:X}]")
})?;
Ok(())
}
#[allow(dead_code)]
fn mem_read(&mut self, address: u64, size: usize) -> Result<Cow<[u8]>, String> {
// Allocate a buffer
let mut buffer = Vec::with_capacity(size);
buffer.resize(size, 0);
// Read the memory
match self.vm.cpu.mem.read_bytes(address, &mut buffer[..], perm::NONE) {
Ok(_) => Ok(Cow::Owned(buffer)),
Err(_) => Err(format!("Failed to read memory {address:X}[{size:X}]"))
}
}
fn mem_write(&mut self, address: u64, data: Vec<u8>) -> Result<(), String> {
let size = data.len();
match self.vm.cpu.mem.write_bytes(address, &data[..], perm::NONE) {
Ok(_) => Ok(()),
Err(_) => Err(format!("Failed to write memory {address:X}[{size:X}]"))
}
}
#[allow(dead_code)]
fn reg_list(&self) -> IndexMap<String, (u32, u8)> {
let mut result = IndexMap::new();
let sleigh = self.vm.cpu.sleigh();
for reg in &sleigh.named_registers {
let name = sleigh.get_str(reg.name);
result.insert(name.to_string(), (reg.offset, reg.var.size));
}
return result;
}
#[allow(dead_code)]
fn reg_offset(&self, name: &str) -> Result<u32, String> {
Ok(reg_find(self, name)?.offset)
}
#[allow(dead_code)]
fn reg_size(&self, name: &str) -> Result<u8, String> {
Ok(reg_find(self, name)?.var.size)
}
fn reg_read(&mut self, name: &str) -> Result<u64, String> {
Ok(self.vm.cpu.read_reg(reg_find(self, name)?.var))
}
fn reg_write(&mut self, name: &str, value: u64) -> Result<(), String> {
Ok(self.vm.cpu.write_reg(reg_find(self, name)?.var, value))
}
#[allow(dead_code)]
fn reset(&mut self) {
self.vm.reset();
}
fn run(&mut self) -> VmExit {
self.vm.run()
}
#[allow(dead_code)]
fn run_until(&mut self, address: u64) -> VmExit {
let breakpoint_added = self.vm.add_breakpoint(address);
let status = self.run();
if breakpoint_added {
self.vm.remove_breakpoint(address);
}
status
}
#[allow(dead_code)]
fn step(&mut self, count: u64) -> VmExit {
let old_limit = self.vm.icount_limit;
self.vm.icount_limit = self.vm.cpu.icount.saturating_add(count);
let status = self.run();
self.vm.icount_limit = old_limit;
status
}
#[allow(dead_code)]
fn add_breakpoint(&mut self, address: u64) -> bool {
self.vm.add_breakpoint(address)
}
#[allow(dead_code)]
fn remove_breakpoint(&mut self, address: u64) -> bool {
self.vm.remove_breakpoint(address)
}
}
#[allow(dead_code)]
fn architectures() -> Result<Vec<&'static str>, String> {
Ok(vec![
"i686",
"x86_64",
"aarch64",
])
}
fn nx_start() {
let mut vm = Icicle::new(
"x86_64".to_string(),
false,
true,
true,
true,
false,
true,
true,
false,
).unwrap();
let page = 0x10000;
vm.mem_map(page, 0x1000, MemoryProtection::ReadOnly).unwrap();
// <non-executable memory> inc eax; ret
vm.mem_write(page, b"\xFF\xC0\xC3".to_vec()).unwrap();
vm.reg_write("rip", page).unwrap();
let status = vm.run();
println!("status: {:?}", status);
println!("rip: {:#x}", vm.reg_read("rip").unwrap());
}
fn nx_middle() {
let mut vm = Icicle::new(
"x86_64".to_string(),
false,
true,
true,
true,
false,
true,
true,
false,
).unwrap();
let page = 0x10000;
vm.mem_map(page, 0x2000, MemoryProtection::ExecuteRead).unwrap();
vm.mem_protect(page + 0x1000, 0x1000, MemoryProtection::ReadOnly).unwrap();
// inc eax; inc eax; <transition to non-executable region>; ret
let rip = page + 0x1000 - 2;
vm.mem_write(rip, b"\xFF\xC0\xFF\xC0\xC3".to_vec()).unwrap();
vm.reg_write("rip", rip).unwrap();
let status = vm.run();
println!("status: {:?}", status);
println!("rip: {:#x}", vm.reg_read("rip").unwrap());
println!("rax: {:#x}", vm.reg_read("rax").unwrap());
}
fn inv_start() {
let mut vm = Icicle::new(
"x86_64".to_string(),
false,
true,
true,
true,
false,
true,
true,
false,
).unwrap();
let page = 0x10000;
vm.mem_map(page, 0x1000, MemoryProtection::ExecuteRead).unwrap();
// <invalid>; ret
vm.mem_write(page, b"\xFF\xFF\xC3".to_vec()).unwrap();
vm.reg_write("rip", page).unwrap();
let status = vm.run();
println!("status: {:?}", status);
println!("rip: {:#x}", vm.reg_read("rip").unwrap());
println!("rax: {:#x}", vm.reg_read("rax").unwrap());
}
fn inv_middle() {
let mut vm = Icicle::new(
"x86_64".to_string(),
false,
true,
true,
true,
false,
true,
true,
false,
).unwrap();
let page = 0x10000;
vm.mem_map(page, 0x1000, MemoryProtection::ExecuteRead).unwrap();
// inc eax; <invalid>; ret
vm.mem_write(page, b"\xFF\xC0\xFF\xFF\xC3".to_vec()).unwrap();
vm.reg_write("rip", page).unwrap();
let status = vm.run();
println!("status: {:?}", status);
println!("rip: {:#x}", vm.reg_read("rip").unwrap());
println!("rax: {:#x}", vm.reg_read("rax").unwrap());
}
fn main() {
println!("=== NX (block start) ===");
nx_start();
println!("=== NX (block middle) ===");
nx_middle();
println!("=== Invalid instruction (block start) ===");
inv_start();
println!("=== Invalid instruction (block middle) ===");
inv_middle();
}
+2
View File
@@ -0,0 +1,2 @@
[env]
GHIDRA_SRC = { value = "../python/icicle", relative = true }
+1163
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "tests"
edition = "2021"
[[bin]]
name = "tests"
path = "tests.rs"
[dependencies]
icicle-python = { path = "..", default-features = false }
pyo3 = { workspace = true, features = ["auto-initialize"] }
+36
View File
@@ -0,0 +1,36 @@
from icicle import *
def main():
emu = Icicle("x86_64", jit=True, optimize_block=True, tracing=True)
instructions = bytes.fromhex("41 C1 EA 07 41 83 E2 1F 74 08 44 89 D0 48 89 54 C6 08 49 83 C1 04 4C 89 0E 4C 89 C9 44 8B 11 44 89 D0 F7 D0 49 89 C9 A8 03 0F 84 88 F6 FF FF EB 4C".replace(" ", ""))
addr = 0x140001A73
heap = 0x71000
emu.mem_map(heap, 0x1000, MemoryProtection.ReadWrite)
emu.mem_write(heap + 4, 0x1337.to_bytes(4, "little"))
emu.mem_map(addr & ~0xFFF, 0x1000, MemoryProtection.ExecuteRead)
emu.mem_write(addr, instructions)
emu.reg_write("r9", heap)
emu.reg_write("r10", 0x13)
emu.reg_write("rip", addr)
emu.reg_write("rsi", heap + 0x100)
for i in range(11):
rip = emu.reg_read("rip")
rcx = emu.reg_read("rcx")
r9 = emu.reg_read("r9")
print(f"[{i}] RIP: {hex(rip)}, RCX: {hex(rcx)}, R9: {hex(r9)}")
if rip == 0x140001A8F:
emu.reg_write("r9", 0x13370900)
emu.step(1)
if rip == 0x140001A9A:
assert rcx == r9, f"expected rcx({hex(rcx)}) == r9({hex(r9)})"
print("Everything works!")
if __name__ == "__main__":
main()
+397
View File
@@ -0,0 +1,397 @@
#![allow(unused)]
use icicle::*;
use pyo3::PyResult;
use std::process::exit;
// NOTE: https://github.com/rust-lang/rust-analyzer/issues/18752
#[test]
fn example() -> PyResult<()> {
Err(pyo3::exceptions::PyException::new_err("test"))
}
fn new_vm(jit: bool) -> PyResult<Icicle> {
Icicle::new(
"x86_64".to_string(),
jit,
true,
false,
true,
false,
true,
false,
false,
)
}
fn new_trace_vm(jit: bool) -> PyResult<Icicle> {
Icicle::new(
"x86_64".to_string(),
jit,
true,
false,
true,
false,
true,
false,
true,
)
}
fn nx_start() -> PyResult<()> {
let mut vm = new_vm(false)?;
let page = 0x10000;
vm.mem_map(page, 0x1000, MemoryProtection::ReadOnly)?;
// <non-executable memory> inc eax; ret
vm.mem_write(page, b"\xFF\xC0\xC3".to_vec())?;
vm.reg_write("rip", page)?;
let status = vm.run();
println!("status: {:?}", status);
println!("rip: {:#x}", vm.reg_read("rip")?);
Ok(())
}
fn nx_middle() -> PyResult<()> {
let mut vm = new_vm(false)?;
let page = 0x10000;
vm.mem_map(page, 0x2000, MemoryProtection::ExecuteRead)?;
vm.mem_protect(page + 0x1000, 0x1000, MemoryProtection::ReadOnly)?;
// inc eax; inc eax; <transition to non-executable region>; ret
let rip = page + 0x1000 - 2;
vm.mem_write(rip, b"\xFF\xC0\xFF\xC0\xC3".to_vec())?;
vm.reg_write("rip", rip)?;
let status = vm.run();
println!("status: {:?}", status);
println!("rip: {:#x}", vm.reg_read("rip")?);
println!("rax: {:#x}", vm.reg_read("rax")?);
Ok(())
}
fn inv_start() -> PyResult<()> {
let mut vm = new_vm(false)?;
let page = 0x10000;
vm.mem_map(page, 0x1000, MemoryProtection::ExecuteRead)?;
// <invalid>; ret
vm.mem_write(page, b"\xFF\xFF\xC3".to_vec())?;
vm.reg_write("rip", page)?;
let status = vm.run();
println!("status: {:?}", status);
println!("rip: {:#x}", vm.reg_read("rip")?);
println!("rax: {:#x}", vm.reg_read("rax")?);
Ok(())
}
fn inv_middle() -> PyResult<()> {
let mut vm = new_vm(false)?;
let page = 0x10000;
vm.mem_map(page, 0x1000, MemoryProtection::ExecuteRead)?;
// inc eax; <invalid>; ret
vm.mem_write(page, b"\xFF\xC0\xFF\xFF\xC3".to_vec())?;
vm.reg_write("rip", page)?;
let status = vm.run();
println!("status: {:?}", status);
println!("rip: {:#x}", vm.reg_read("rip")?);
println!("rax: {:#x}", vm.reg_read("rax")?);
Ok(())
}
fn block_optimization() -> PyResult<()> {
let mut vm: Icicle = Icicle::new(
"x86_64".to_string(),
true,
true,
true,
true,
false,
true,
true,
false,
)?;
// Memory setup
let addr: u64 = 0x140001A73;
let heap: u64 = 0x71000;
vm.mem_map(heap, 0x1000, MemoryProtection::ReadWrite)?;
vm.mem_write(heap + 4, b"\x37\x13\x00\x00".to_vec())?;
vm.mem_map(addr & !0xFFF, 0x1000, MemoryProtection::ExecuteRead)?;
vm.mem_write(addr, b"\x41\xc1\xea\x07\x41\x83\xe2\x1f\x74\x08\x44\x89\xd0\x48\x89\x54\xc6\x08\x49\x83\xc1\x04\x4c\x89\x0e\x4c\x89\xc9\x44\x8b\x11\x44\x89\xd0\xf7\xd0\x49\x89\xc9\xa8\x03\x0f\x84\x88\xf6\xff\xff\xeb\x4c\xcc".to_vec())?;
// Register setup
vm.reg_write("r9", heap)?;
vm.reg_write("r10", 0x13)?;
vm.reg_write("rip", addr)?;
vm.reg_write("rsi", heap + 0x100)?;
// Step through instructions
for i in 0..11 {
let rip = vm.reg_read("rip")?;
let rcx = vm.reg_read("rcx")?;
let r9 = vm.reg_read("r9")?;
println!("[{}] RIP: {:#x}, RCX: {:#x}, R9: {:#x}", i, rip, rcx, r9);
if rip == 0x140001A8F {
vm.reg_write("r9", 0x13370900)?;
}
vm.step(1);
if rip == 0x140001A9A {
if rcx != r9 {
println!("[BUG] expected rcx({:#x}) == r9({:#x})", rcx, r9);
} else {
println!("Everything works!");
}
}
}
Ok(())
}
fn rewind() -> PyResult<()> {
let mut vm = new_vm(true)?;
vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteRead)?;
vm.mem_map(0x200, 0x20, MemoryProtection::ReadOnly)?;
vm.mem_write(0x100, b"\x55\xCC".to_vec())?; // push rbp
vm.reg_write("rbp", 0xF00)?;
vm.reg_write("rsp", 0x210)?;
vm.reg_write("rip", 0x100)?;
let status = vm.step(1);
println!("run status : {:?}", status);
println!("exception code : {:?}", vm.get_exception_code());
println!("exception value : {:#x}", vm.get_exception_value());
println!("stack pointer : {:#x}", vm.reg_read("rsp")?);
Ok(())
}
fn execute_uninitialized() -> PyResult<()> {
let mut vm = Icicle::new(
"x86_64".to_string(),
true,
true,
false,
true,
true, // NOTE: setting this to true is not properly supported
true,
false,
false,
)?;
// \x48\x8d\x05\x01\x00\x00\x00\x90\x8a\x18\x90
vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteOnly)?;
vm.mem_write(0x100, b"\x90\xFF\xC0".to_vec())?; // inc eax
vm.reg_write("rip", 0x100)?;
{
println!("[pre1] icount: {}", vm.get_icount());
let status = vm.step(2);
// NOTE: the real reason is that INIT is not set
println!("run status : {:?}", status);
println!("exception code : {:?}", vm.get_exception_code());
println!("exception value : {:#x}", vm.get_exception_value());
println!("rax : {:#x}", vm.reg_read("rax")?);
}
{
println!("[pre2] icount: {}", vm.get_icount());
let status = vm.step(1);
// NOTE: the real reason is that INIT is not set
println!("run status : {:?}", status);
println!("exception code : {:?}", vm.get_exception_code());
println!("exception value : {:#x}", vm.get_exception_value());
println!("rax : {:#x}", vm.reg_read("rax")?);
println!("[post] icount: {}", vm.get_icount());
}
// TODO: status is now UnhandledException, should be InstructionLimit
// on the next stpe it should be UnhandledException -> ExecViolation
Ok(())
}
fn execute_only() -> PyResult<()> {
let mut vm = new_vm(false)?;
vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteOnly)?;
/*
0x100: lea rax, [rip]
0x107: nop
0x108: mov bl, byte ptr [rax]
0x10A: int3
*/
vm.mem_write(
0x100,
b"\x48\x8d\x05\x00\x00\x00\x00\x90\x8a\x18\xCC".to_vec(),
)?; // nop
vm.reg_write("rip", 0x100)?;
vm.step(2);
let status = vm.step(1);
// NOTE: the real reason is that INIT is not set
println!("run status : {:?}", status);
println!("exception code : {:?}", vm.get_exception_code());
println!("exception value : {:#x}", vm.get_exception_value());
println!("bl: {:#x}", vm.reg_read("bl")?);
println!("rip: {:#x}", vm.reg_read("rip")?);
Ok(())
}
fn self_modifying() -> PyResult<()> {
// TODO: add a self-modifying code check (where the previously-executed code is written to)
Ok(())
}
fn step_modify_rip() -> PyResult<()> {
let mut vm = new_vm(false)?;
vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteRead)?;
// 0x100: 48 01 d8 add rax,rbx
// 0x103: 48 83 e9 05 sub rcx,0x5
// 0x107: 48 89 d9 mov rcx,rbx
// 0x10a: 90 nop
// 0x10b: 90 nop
vm.mem_write(
0x100,
b"\x48\x01\xD8\x48\x83\xE9\x05\x48\x89\xD9\x90\x90\xCC".to_vec(),
)?;
vm.reg_write("rax", 0xF00)?;
vm.reg_write("rbx", 0x210)?;
vm.reg_write("rip", 0x100)?;
println!("starting run at {:#x}", vm.reg_read("rip")?);
let mut status = vm.step(1);
println!(
"ending run at {:#x} (status: {:?})",
vm.reg_read("rip")?,
status
);
vm.reg_write("rip", 0x100)?;
//vm.write_pc(0x100);
//println!("pc: {:#x}", vm.read_pc());
println!("rip rewritten {:#x}", vm.reg_read("rip")?);
status = vm.step(1);
println!(
"ending run at {:#x} (status: {:?})",
vm.reg_read("rip")?,
status
);
Ok(())
}
fn eflags_reconstruction() -> PyResult<()> {
let mut vm = new_vm(false)?;
vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteRead)?;
vm.mem_write(0x100, b"\x48\x01\xD8\xCC".to_vec())?;
vm.reg_write("rax", 0x7FFFFFFFFFFFFFFF)?;
vm.reg_write("rbx", 0x1)?;
let of_mask = (1 << 11) as u64;
{
let eflags = vm.reg_read("eflags")?;
let of = vm.reg_read("OF")?;
let of_set = (eflags & of_mask) == of_mask;
println!("[pre] eflags: {:#x}, OF: {:#x} == {}", eflags, of, of_set);
}
vm.set_pc(0x100);
let status = vm.step(1);
println!("run status: {:?}", status);
{
let eflags = vm.reg_read("eflags")?;
let rflags = vm.reg_read("rflags")?;
let of = vm.reg_read("OF")?;
let of_set = (eflags & of_mask) == of_mask;
println!(
"[post] eflags: {:#x} == {:#x}, OF: {:#x} == {}",
eflags, rflags, of, of_set
);
}
{
vm.reg_write("OF", 0)?;
let eflags = vm.reg_read("eflags")?;
let of = vm.reg_read("OF")?;
let of_set = (eflags >> 11) & 1;
println!("[OF=0] eflags: {:#x}, OF: {:#x} == {}", eflags, of, of_set);
}
{
let mut eflags = vm.reg_read("eflags")?;
eflags |= of_mask;
vm.reg_write("rflags", eflags)?;
let of = vm.reg_read("OF")?;
let of_set = (eflags >> 11) & 1;
println!(
"[rflags|={:#x}] eflags: {:#x}, OF: {:#x} == {}",
of_mask, eflags, of, of_set
);
}
Ok(())
}
fn main() {
// Make sure the GHIDRA_SRC environment variable is valid
match std::env::var("GHIDRA_SRC") {
Ok(ghidra_src) => {
// Make sure the directory $GHIDRA_SRC/Ghidra/Processors exists
if !std::path::Path::new(&ghidra_src)
.join("Ghidra")
.join("Processors")
.exists()
{
println!("GHIDRA_SRC environment variable invalid!");
exit(1);
}
println!("GHIDRA_SRC: {}", ghidra_src);
}
Err(_) => {
println!("GHIDRA_SRC environment variable not set!");
exit(1);
}
}
let tests: Vec<(&str, fn() -> PyResult<()>)> = vec![
//("NX (block start)", nx_start),
//("NX (block middle)", nx_middle),
//("Invalid instruction (block start)", inv_start),
//("Invalid instruction (block middle)", inv_middle),
//("Block optimization bug", block_optimization),
//("Rewind", rewind),
//("Execute only", execute_only),
("Execute uninitialized", execute_uninitialized),
//("Step modify rip", step_modify_rip),
//("EFlags reconstruction", eflags_reconstruction),
];
let mut success = 0;
for (name, f) in tests.iter() {
println!("=== {} ===", name);
match f() {
Ok(_) => {
success += 1;
println!("[OK]");
}
Err(e) => {
println!("[ERROR] {}", e);
}
}
}
println!("{}/{} tests passed", success, tests.len());
exit(if success == tests.len() { 0 } else { 1 });
}