diff --git a/.github/workflows/Crate-publishing.yml b/.github/workflows/Crate-publishing.yml index eb1e0470..e20ba172 100644 --- a/.github/workflows/Crate-publishing.yml +++ b/.github/workflows/Crate-publishing.yml @@ -67,6 +67,12 @@ jobs: run: | choco install ninja cmake + - name: '🛠️ macOS build dependencies' + if: contains(matrix.config.os, 'macOS') + shell: bash + run: | + brew install p7zip cmake ninja pkg-config + - name: '🚧 Cargo test' if: "!startsWith(github.ref, 'refs/tags')" run: | diff --git a/.github/workflows/Nuget-publishing.yml b/.github/workflows/Nuget-publishing.yml new file mode 100644 index 00000000..e82961cd --- /dev/null +++ b/.github/workflows/Nuget-publishing.yml @@ -0,0 +1,438 @@ +name: Nuget 📦 Distribution + +on: + push: + paths-ignore: + - ".gitignore" + - "docs/**" + - "README" + - "CREDITS.TXT" + - "COPYING_GLIB" + - "COPYING.LGPL2" + - "AUTHORS.TXT" + - "CHANGELOG" + - "COPYING" + branches: + - dev + - master + +permissions: + packages: write + +jobs: + Windows: + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.name }} + strategy: + fail-fast: true + matrix: + config: + - { + os: windows-2019, + arch: x64, + python-arch: x64, + python-ver: '3.8', + name: 'windows-x64 MSVC 64bit shared', + msvc-arch: x64, + artifact: 'windows_msvc64_shared.7z', + shared: 'yes', + build_type: 'Release', + archiver: '7z a', + generators: 'Visual Studio 16 2019' + } + - { + os: windows-2019, + arch: x86, + python-arch: x86, + python-ver: '3.8', + name: 'windows-x86 MSVC 32bit shared', + msvc-arch: x86, + artifact: 'windows_msvc32_shared.7z', + shared: 'yes', + build_type: 'Release', + archiver: '7z a', + generators: 'Visual Studio 16 2019' + } + compiler: [ gcc ] + steps: + - uses: actions/checkout@v2 + + - name: '🛠️ Win MSVC 64 setup' + if: contains(matrix.config.name, 'MSVC 64') + uses: microsoft/setup-msbuild@v1 + + - name: '🛠️ Win MSVC 64 dev cmd setup' + if: contains(matrix.config.name, 'MSVC 64') + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: '🚧 Win MSVC 64 build' + if: contains(matrix.config.name, 'MSVC 64') + shell: bash + run: | + choco install ninja cmake + ninja --version + cmake --version + mkdir build + cmake \ + -S . \ + -B . \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -G "${{ matrix.config.generators }}" \ + -DCMAKE_C_FLAGS="//MT" \ + -DCMAKE_INSTALL_PREFIX:PATH=instdir \ + -DBUILD_SHARED_LIBS=${{ matrix.config.shared }} + cmake --build . --config ${{ matrix.config.build_type }} + cmake --install . --strip --config ${{ matrix.config.build_type }} + ctest -VV -C ${{ matrix.config.build_type }} + mv Release instdir + + - name: '🛠️ Win MSVC 32 setup' + if: contains(matrix.config.name, 'MSVC 32') + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x86 + + - name: '🚧 Win MSVC 32 build' + if: contains(matrix.config.name, 'MSVC 32') + shell: bash + run: | + choco install ninja cmake + ninja --version + cmake --version + mkdir build + cmake \ + -S . \ + -B . \ + -A "win32" \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -G "${{ matrix.config.generators }}" \ + -DCMAKE_C_FLAGS="//MT" \ + -DCMAKE_INSTALL_PREFIX:PATH=instdir \ + -DBUILD_SHARED_LIBS=${{ matrix.config.shared }} + cmake --build . --config ${{ matrix.config.build_type }} + cmake --install . --strip --config ${{ matrix.config.build_type }} + ctest -VV -C ${{ matrix.config.build_type }} + mv Release instdir + + - name: '📦 Pack artifact' + if: always() + shell: bash + working-directory: instdir + run: | + ls -laR + ${{ matrix.config.archiver }} ../${{ matrix.config.artifact }} . ../test* + + - name: '📤 Upload artifact' + if: always() + uses: actions/upload-artifact@v2 + with: + path: ./${{ matrix.config.artifact }} + name: ${{ matrix.config.artifact }} + + Macos: + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.name }} - ${{ matrix.compiler }} + strategy: + fail-fast: true + matrix: + config: + - { + os: macos-latest, + arch: x64, + python-arch: x64, + python-ver: '3.8', + name: 'macos-x64 cmake shared', + shared: 'yes', + artifact: 'macos-cmake-shared-x64.7z', + build_type: 'Release', + archiver: '7za a', + generators: 'Ninja' + } + compiler: [ gcc ] + steps: + - uses: actions/checkout@v2 + + - name: '🚧 Mac build' + if: contains(matrix.config.name, 'macos-x64') + shell: bash + run: | + brew install p7zip cmake ninja pkg-config + ninja --version + cmake --version + mkdir build + mkdir instdir + cmake \ + -S . \ + -B . \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -G "${{ matrix.config.generators }}" \ + -DCMAKE_INSTALL_PREFIX:PATH=instdir \ + -DBUILD_SHARED_LIBS=${{ matrix.config.shared }} + cmake --build . --config ${{ matrix.config.build_type }} + cmake --install . --strip + ctest -VV -C ${{ matrix.config.build_type }} + + - name: '📦 Pack artifact' + if: always() + shell: bash + working-directory: instdir + run: | + ls -laR + ${{ matrix.config.archiver }} ../${{ matrix.config.artifact }} . ../test* + + - name: '📤 Upload artifact' + if: always() + uses: actions/upload-artifact@v2 + with: + path: ./${{ matrix.config.artifact }} + name: ${{ matrix.config.artifact }} + + Linux: + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.name }} - ${{ matrix.compiler }} + strategy: + fail-fast: false + matrix: + config: + - { + os: ubuntu-latest, + arch: x64, + python-arch: x64, + python-ver: '3.8', + name: 'ubuntu-x64 cmake shared', + shared: 'yes', + artifact: 'ubuntu-cmake-shared-x64.7z', + build_type: 'Release', + archiver: '7z a', + generators: 'Ninja' + } + - { + os: ubuntu-latest, + arch: x86, + python-arch: x86, + python-ver: '3.8', + name: 'ubuntu-x86 cmake shared', + shared: 'yes', + artifact: 'ubuntu-cmake-shared-x86.7z', + build_type: 'Release', + archiver: '7z a', + generators: 'Ninja' + } + - { + os: ubuntu-latest, + arch: aarch64, + python-arch: aarch64, + python-ver: '3.8', + name: 'ubuntu-aarch64 cmake', + artifact: 'ubuntu-cmake-aarch64.7z', + build_type: 'Release', + archiver: '7z a', + generators: 'Ninja', + distro: ubuntu20.04 + } + - { + os: ubuntu-latest, + arch: ppc64le, + python-arch: ppc, + python-ver: '3.8', + name: 'ubuntu-ppc64le cmake', + artifact: 'ubuntu-cmake-ppc64le.7z', + build_type: 'Release', + archiver: '7z a', + generators: 'Ninja', + distro: ubuntu20.04 + } + compiler: [ gcc ] + steps: + - uses: actions/checkout@v2 + + - name: '🚧 Linux x64/x86 build' + if: contains(matrix.config.arch, 'x64') || contains(matrix.config.arch, 'x86') + shell: 'script -q -e -c "bash {0}"' + run: | + if [ ${{ matrix.config.arch }} == 'x64' ]; then + sudo apt install -q -y libcmocka-dev ninja-build + else + export CFLAGS="-m32" LDFLAGS="-m32" LDFLAGS_STATIC="-m32" UNICORN_QEMU_FLAGS="--cpu=i386" + sudo dpkg --add-architecture i386 + sudo apt install -q -y lib32ncurses-dev lib32z1-dev lib32gcc-9-dev libc6-dev-i386 gcc-multilib \ + libcmocka-dev:i386 libcmocka0:i386 libc6:i386 libgcc-s1:i386 ninja-build + fi + mkdir build + mkdir instdir + cmake \ + -S . \ + -B . \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -G "${{ matrix.config.generators }}" \ + -DCMAKE_INSTALL_PREFIX:PATH=instdir \ + -DBUILD_SHARED_LIBS=${{ matrix.config.shared }} + cmake --build . --config ${{ matrix.config.build_type }} + cmake --install . --strip + ctest -VV -C ${{ matrix.config.build_type }} + + - name: '🚧 Linux ppc64le/aarch64 build' + if: contains(matrix.config.arch, 'ppc64le') || contains(matrix.config.arch, 'aarch64') + uses: uraimo/run-on-arch-action@v2.0.5 + with: + arch: ${{ matrix.config.arch }} + distro: ${{ matrix.config.distro }} + setup: | + mkdir -p "${PWD}/instdir" + dockerRunArgs: | + --volume "${PWD}/instdir:/instdir" + shell: /bin/sh + install: | + apt-get update -q -y + apt-get install -q -y git cmake build-essential automake libcmocka-dev pkg-config ${{ matrix.compiler }} ninja-build + run: | + mkdir build + cmake \ + -S . \ + -B . \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -G "${{ matrix.config.generators }}" \ + -DCMAKE_INSTALL_PREFIX:PATH=/instdir + cmake --build . --config ${{ matrix.config.build_type }} + cmake --install . --strip + ctest -VV -C ${{ matrix.config.build_type }} + + - name: '📦 Pack artifact' + if: always() + shell: bash + working-directory: instdir + run: | + ls -laR + ${{ matrix.config.archiver }} ../${{ matrix.config.artifact }} . ../test* + + - name: '📤 Upload artifact' + if: always() + uses: actions/upload-artifact@v2 + with: + path: ./${{ matrix.config.artifact }} + name: ${{ matrix.config.artifact }} + + publish: + needs: ["Windows", "Macos", "Linux"] + if: ${{ needs.Windows.result == 'success' && needs.Macos.result == 'success' && needs.Linux.result == 'success' }} + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: 🛠️ Download artifacts + uses: actions/download-artifact@v3 + with: + path: artifacts + + - name: 🛠️ Extract artifacts + shell: python + run: | + import subprocess + import os + + artifactPath = os.path.join(os.getcwd(), "artifacts") + bindingsPath = os.path.join(os.getcwd(), "bindings", "dotnet", "UnicornEngine") + + ARTIFACT_CONFIG = { + "ubuntu-cmake-aarch64.7z": { + "sourceDir": "lib/", + "sourceFile": "libunicorn.so.*", + "destDir": "runtimes/linux-arm64/native", + "destFile": "libunicorn.so" + }, + "ubuntu-cmake-ppc64le.7z": { + "sourceDir": "lib/", + "sourceFile": "libunicorn.so.*", + "destDir": "runtimes/linux-ppc64le/native", + "destFile": "libunicorn.so" + }, + "ubuntu-cmake-shared-x86.7z": { + "sourceDir": "lib/", + "sourceFile": "libunicorn.so.*", + "destDir": "runtimes/linux-x64/native", + "destFile": "libunicorn.so" + }, + "macos-cmake-shared-x64.7z": { + "sourceDir": "lib/", + "sourceFile": "libunicorn.*.dylib", + "destDir": "runtimes/osx-x64/native", + "destFile": "libunicorn.dylib" + }, + "windows_msvc64_shared.7z": { + "sourceDir": "", + "sourceFile": "unicorn.dll", + "destDir": "runtimes/win-x64/native", + "destFile": "unicorn.dll" + }, + "windows_msvc32_shared.7z": { + "sourceDir": "", + "sourceFile": "unicorn.dll", + "destDir": "runtimes/win-x86/native", + "destFile": "unicorn.dll" + } + } + + if len(os.listdir(artifactPath)) < len(ARTIFACT_CONFIG.keys()): + print("Some artifacts are missing. Aborting.") + exit(1) + + for artifact in os.listdir(artifactPath): + if artifact in ARTIFACT_CONFIG.keys(): + print("Working on:", artifact) + config = ARTIFACT_CONFIG[artifact] + destDir = os.path.join(bindingsPath, config["destDir"]) + print("Creating dir:", destDir) + os.makedirs(destDir, exist_ok=True) + + print(f"Extracting library from 7z file to: {config['destDir']}/{config['sourceFile']}") + result = subprocess.run(["7z", "e", f"-o{destDir}/", os.path.join(artifactPath, artifact), f"{config['sourceDir']}{config['sourceFile']}"]) + result.check_returncode() + + if config["sourceFile"] != config["destFile"]: + output = subprocess.run(["ls", destDir], stdout=subprocess.PIPE) + sourceFile = output.stdout.decode().strip() + print(f"Renaming {sourceFile} to {config['destFile']}") + os.rename(os.path.join(destDir, sourceFile), os.path.join(destDir, config["destFile"])) + + print("Done!") + + - name: 🛠️ Get short sha + id: git_short_sha + run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT + + - uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.0.x + + - name: 🛠️ Authenticate to Github Packages + working-directory: bindings/dotnet/UnicornEngine + run: dotnet nuget add source --username "${{ github.repository_owner }}" --password "${{ secrets.GITHUB_TOKEN }}" --store-password-in-clear-text --name github "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" + + - name: 🛠️ List all native libraries + working-directory: bindings/dotnet/UnicornEngine + run: find ./runtimes -type f -print + + - name: 🚧 Package .NET distribution + working-directory: bindings/dotnet/UnicornEngine + run: | + [[ "${{ github.ref_name }}" == "master" ]] \ + && dotnet pack -c Release \ + || dotnet pack -c Release --version-suffix="${{ steps.git_short_sha.outputs.result }}" + + - name: '📤 Upload artifact' + uses: actions/upload-artifact@v2 + with: + path: ${{ github.workspace }}/bindings/dotnet/UnicornEngine/bin/Release/UnicornEngine.Unicorn.*.nupkg + + - name: 📦 Publish to Github Packages + working-directory: bindings/dotnet/UnicornEngine + run: dotnet nuget push "bin/Release/UnicornEngine.Unicorn.*.nupkg" --source "github" --api-key "${{ secrets.GHPR_TOKEN }}" + + - name: 📦 Publish Nuget package + working-directory: bindings/dotnet/UnicornEngine + run: dotnet nuget push "bin/Release/UnicornEngine.Unicorn.*.nupkg" -k "$NUGET_AUTH_TOKEN" -s https://api.nuget.org/v3/index.json + env: + NUGET_AUTH_TOKEN: ${{ secrets.NUGET_KEY }} diff --git a/.github/workflows/PyPI-publishing.yml b/.github/workflows/PyPI-publishing.yml index 5f254bc2..b152c144 100644 --- a/.github/workflows/PyPI-publishing.yml +++ b/.github/workflows/PyPI-publishing.yml @@ -96,7 +96,12 @@ jobs: run: | choco install ninja cmake - - name: '🛠️ Install dependencies' + - name: '🛠️ macOS dependencies' + if: contains(matrix.config.name, 'macos') + run: | + brew install p7zip cmake ninja pkg-config + + - name: '🛠️ pip dependencies' run: | pip install setuptools wheel diff --git a/.github/workflows/build-uc2.yml b/.github/workflows/build-uc2.yml index 7ee95894..ded889ef 100644 --- a/.github/workflows/build-uc2.yml +++ b/.github/workflows/build-uc2.yml @@ -305,7 +305,7 @@ jobs: if: contains(matrix.config.name, 'macos-x64') shell: bash run: | - brew install p7zip cmake ninja + brew install p7zip cmake ninja pkg-config ninja --version cmake --version mkdir build @@ -325,7 +325,7 @@ jobs: if: contains(matrix.config.name, 'android') shell: bash run: | - brew install p7zip cmake ninja + brew install p7zip cmake ninja pkg-config mkdir build mkdir instdir cmake . -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK/build/cmake/android.toolchain.cmake" \ diff --git a/Brewfile b/Brewfile deleted file mode 100644 index 82c65634..00000000 --- a/Brewfile +++ /dev/null @@ -1,6 +0,0 @@ -# Travis CI setup for MacOS Brew - -# used for testing framework -brew "cmocka" -# used for cross assembly of code for testing -brew "crosstool-ng" diff --git a/CMakeLists.txt b/CMakeLists.txt index 4110ae53..d94bd464 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ set(CMAKE_C_STANDARD 11) set(UNICORN_VERSION_MAJOR 2) set(UNICORN_VERSION_MINOR 0) -set(UNICORN_VERSION_PATCH 1) +set(UNICORN_VERSION_PATCH 2) include(bundle_static.cmake) diff --git a/Cargo.toml b/Cargo.toml index 86ff6dc6..46f7c742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "unicorn-engine" -version = "2.0.1" +version = "2.0.2" authors = ["Ziqiao Kong", "Lukas Seidel"] documentation = "https://github.com/unicorn-engine/unicorn/wiki" edition = "2021" @@ -40,5 +40,16 @@ cmake = { version = "0.1" } pkg-config = { version = "0.3" } [features] -default = [] +default = ["arch_all"] dynamic_linkage = [] +arch_all = ["arch_x86", "arch_arm", "arch_aarch64", "arch_riscv", "arch_mips", "arch_sparc", "arch_m68k", "arch_ppc", "arch_s390x", "arch_tricore"] +arch_x86 = [] +arch_arm = [] +arch_aarch64 = [] +arch_riscv = [] +arch_mips = [] +arch_sparc = [] +arch_m68k = [] +arch_ppc = [] +arch_s390x = [] +arch_tricore = [] diff --git a/bindings/const_generator.py b/bindings/const_generator.py index 4c5d1e76..b2607031 100644 --- a/bindings/const_generator.py +++ b/bindings/const_generator.py @@ -90,10 +90,10 @@ template = { 'comment_close': '', }, 'dotnet': { - 'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\nnamespace UnicornManaged.Const\n\nopen System\n\n[]\nmodule %s =\n", + 'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\nnamespace UnicornEngine.Const\n\nopen System\n\n[]\nmodule %s =\n", 'footer': "\n", 'line_format': ' let UC_%s = %s\n', - 'out_file': os.path.join('dotnet', 'UnicornManaged', 'Const', '%s.fs'), + 'out_file': os.path.join('dotnet', 'UnicornEngine', 'Const', '%s.fs'), # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'Arm', 'arm64.h': 'Arm64', diff --git a/bindings/dotnet/UnicornDotNet.sln b/bindings/dotnet/UnicornDotNet.sln index 90aa5b60..abe168e9 100644 --- a/bindings/dotnet/UnicornDotNet.sln +++ b/bindings/dotnet/UnicornDotNet.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicornSamples", "UnicornSamples\UnicornSamples.csproj", "{B80B5987-1E24-4309-8BF9-C4F91270F21C}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UnicornManaged", "UnicornManaged\UnicornManaged.fsproj", "{0C21F1C1-2725-4A46-9022-1905F85822A5}" +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UnicornEngine", "UnicornEngine\UnicornEngine.fsproj", "{0C21F1C1-2725-4A46-9022-1905F85822A5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/bindings/dotnet/UnicornManaged/Binding/BindingFactory.fs b/bindings/dotnet/UnicornEngine/Binding/BindingFactory.fs similarity index 84% rename from bindings/dotnet/UnicornManaged/Binding/BindingFactory.fs rename to bindings/dotnet/UnicornEngine/Binding/BindingFactory.fs index 6ea0b183..30c7f821 100644 --- a/bindings/dotnet/UnicornManaged/Binding/BindingFactory.fs +++ b/bindings/dotnet/UnicornEngine/Binding/BindingFactory.fs @@ -1,4 +1,4 @@ -namespace UnicornManaged.Binding +namespace UnicornEngine.Binding module BindingFactory = diff --git a/bindings/dotnet/UnicornManaged/Binding/IBinding.fs b/bindings/dotnet/UnicornEngine/Binding/IBinding.fs similarity index 97% rename from bindings/dotnet/UnicornManaged/Binding/IBinding.fs rename to bindings/dotnet/UnicornEngine/Binding/IBinding.fs index 7ef6d279..b6c3edc0 100644 --- a/bindings/dotnet/UnicornManaged/Binding/IBinding.fs +++ b/bindings/dotnet/UnicornEngine/Binding/IBinding.fs @@ -1,4 +1,4 @@ -namespace UnicornManaged.Binding +namespace UnicornEngine.Binding open System diff --git a/bindings/dotnet/UnicornManaged/Binding/MockBinding.fs b/bindings/dotnet/UnicornEngine/Binding/MockBinding.fs similarity index 98% rename from bindings/dotnet/UnicornManaged/Binding/MockBinding.fs rename to bindings/dotnet/UnicornEngine/Binding/MockBinding.fs index 7b99c8e5..3eeefe89 100644 --- a/bindings/dotnet/UnicornManaged/Binding/MockBinding.fs +++ b/bindings/dotnet/UnicornEngine/Binding/MockBinding.fs @@ -1,4 +1,4 @@ -namespace UnicornManaged.Binding +namespace UnicornEngine.Binding open System diff --git a/bindings/dotnet/UnicornManaged/Binding/NativeBinding.fs b/bindings/dotnet/UnicornEngine/Binding/NativeBinding.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Binding/NativeBinding.fs rename to bindings/dotnet/UnicornEngine/Binding/NativeBinding.fs index 6be7b2f3..efaccc48 100644 --- a/bindings/dotnet/UnicornManaged/Binding/NativeBinding.fs +++ b/bindings/dotnet/UnicornEngine/Binding/NativeBinding.fs @@ -1,4 +1,4 @@ -namespace UnicornManaged.Binding +namespace UnicornEngine.Binding open System open System.Runtime.InteropServices diff --git a/bindings/dotnet/UnicornManaged/Const/Arm.fs b/bindings/dotnet/UnicornEngine/Const/Arm.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/Arm.fs rename to bindings/dotnet/UnicornEngine/Const/Arm.fs index 08766baf..8a275261 100644 --- a/bindings/dotnet/UnicornManaged/Const/Arm.fs +++ b/bindings/dotnet/UnicornEngine/Const/Arm.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/Arm64.fs b/bindings/dotnet/UnicornEngine/Const/Arm64.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/Arm64.fs rename to bindings/dotnet/UnicornEngine/Const/Arm64.fs index 4c509d03..9e9878a7 100644 --- a/bindings/dotnet/UnicornManaged/Const/Arm64.fs +++ b/bindings/dotnet/UnicornEngine/Const/Arm64.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornEngine/Const/Common.fs similarity index 96% rename from bindings/dotnet/UnicornManaged/Const/Common.fs rename to bindings/dotnet/UnicornEngine/Const/Common.fs index 72b5cb3a..d0ed7b98 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornEngine/Const/Common.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System @@ -9,13 +9,13 @@ module Common = let UC_API_MAJOR = 2 let UC_API_MINOR = 0 - let UC_API_PATCH = 1 - let UC_API_EXTRA = 255 + let UC_API_PATCH = 2 + let UC_API_EXTRA = 1 let UC_VERSION_MAJOR = 2 let UC_VERSION_MINOR = 0 - let UC_VERSION_PATCH = 1 - let UC_VERSION_EXTRA = 255 + let UC_VERSION_PATCH = 2 + let UC_VERSION_EXTRA = 1 let UC_SECOND_SCALE = 1000000 let UC_MILISECOND_SCALE = 1000 let UC_ARCH_ARM = 1 diff --git a/bindings/dotnet/UnicornManaged/Const/M68k.fs b/bindings/dotnet/UnicornEngine/Const/M68k.fs similarity index 97% rename from bindings/dotnet/UnicornManaged/Const/M68k.fs rename to bindings/dotnet/UnicornEngine/Const/M68k.fs index b9189d2d..768bc12b 100644 --- a/bindings/dotnet/UnicornManaged/Const/M68k.fs +++ b/bindings/dotnet/UnicornEngine/Const/M68k.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/Mips.fs b/bindings/dotnet/UnicornEngine/Const/Mips.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/Mips.fs rename to bindings/dotnet/UnicornEngine/Const/Mips.fs index 7f85a0cf..d4818783 100644 --- a/bindings/dotnet/UnicornManaged/Const/Mips.fs +++ b/bindings/dotnet/UnicornEngine/Const/Mips.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/Ppc.fs b/bindings/dotnet/UnicornEngine/Const/Ppc.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/Ppc.fs rename to bindings/dotnet/UnicornEngine/Const/Ppc.fs index 1727c157..54a18b3b 100644 --- a/bindings/dotnet/UnicornManaged/Const/Ppc.fs +++ b/bindings/dotnet/UnicornEngine/Const/Ppc.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/Riscv.fs b/bindings/dotnet/UnicornEngine/Const/Riscv.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/Riscv.fs rename to bindings/dotnet/UnicornEngine/Const/Riscv.fs index bf578024..fe61ec2c 100644 --- a/bindings/dotnet/UnicornManaged/Const/Riscv.fs +++ b/bindings/dotnet/UnicornEngine/Const/Riscv.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/S390x.fs b/bindings/dotnet/UnicornEngine/Const/S390x.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/S390x.fs rename to bindings/dotnet/UnicornEngine/Const/S390x.fs index 97f7ec4b..c4bd76e6 100644 --- a/bindings/dotnet/UnicornManaged/Const/S390x.fs +++ b/bindings/dotnet/UnicornEngine/Const/S390x.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/Sparc.fs b/bindings/dotnet/UnicornEngine/Const/Sparc.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/Sparc.fs rename to bindings/dotnet/UnicornEngine/Const/Sparc.fs index 8eb8cc23..8350af5c 100644 --- a/bindings/dotnet/UnicornManaged/Const/Sparc.fs +++ b/bindings/dotnet/UnicornEngine/Const/Sparc.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/TriCore.fs b/bindings/dotnet/UnicornEngine/Const/TriCore.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/TriCore.fs rename to bindings/dotnet/UnicornEngine/Const/TriCore.fs index 0c82fb97..b2c78e2e 100644 --- a/bindings/dotnet/UnicornManaged/Const/TriCore.fs +++ b/bindings/dotnet/UnicornEngine/Const/TriCore.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/Const/X86.fs b/bindings/dotnet/UnicornEngine/Const/X86.fs similarity index 99% rename from bindings/dotnet/UnicornManaged/Const/X86.fs rename to bindings/dotnet/UnicornEngine/Const/X86.fs index 8d2fd5b3..5e115b9e 100644 --- a/bindings/dotnet/UnicornManaged/Const/X86.fs +++ b/bindings/dotnet/UnicornEngine/Const/X86.fs @@ -1,6 +1,6 @@ // For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT -namespace UnicornManaged.Const +namespace UnicornEngine.Const open System diff --git a/bindings/dotnet/UnicornManaged/ConvertUtility.fs b/bindings/dotnet/UnicornEngine/ConvertUtility.fs similarity index 94% rename from bindings/dotnet/UnicornManaged/ConvertUtility.fs rename to bindings/dotnet/UnicornEngine/ConvertUtility.fs index 5e455bf7..a453c861 100644 --- a/bindings/dotnet/UnicornManaged/ConvertUtility.fs +++ b/bindings/dotnet/UnicornEngine/ConvertUtility.fs @@ -1,4 +1,4 @@ -namespace UnicornManaged +namespace UnicornEngine open System diff --git a/bindings/dotnet/UnicornManaged/InternalHooks.fs b/bindings/dotnet/UnicornEngine/InternalHooks.fs similarity index 84% rename from bindings/dotnet/UnicornManaged/InternalHooks.fs rename to bindings/dotnet/UnicornEngine/InternalHooks.fs index 36cfc3ce..062de03c 100644 --- a/bindings/dotnet/UnicornManaged/InternalHooks.fs +++ b/bindings/dotnet/UnicornEngine/InternalHooks.fs @@ -1,4 +1,4 @@ -namespace UnicornManaged +namespace UnicornEngine open System open System.Runtime.InteropServices @@ -14,10 +14,10 @@ type internal BlockHookInternal = delegate of IntPtr * Int64 * Int32 * IntPtr -> type internal InterruptHookInternal = delegate of IntPtr * Int32 * IntPtr -> unit [] -type internal MemReadHookInternal = delegate of IntPtr * Int64 * Int32 * IntPtr -> unit +type internal MemReadHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * IntPtr -> unit [] -type internal MemWriteHookInternal = delegate of IntPtr * Int64 * Int32 * Int64 * IntPtr -> unit +type internal MemWriteHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * Int64 * IntPtr -> unit [] type internal EventMemHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * Int64 * IntPtr-> Boolean diff --git a/bindings/dotnet/UnicornEngine/Unicorn.fs b/bindings/dotnet/UnicornEngine/Unicorn.fs new file mode 100644 index 00000000..56a683b0 --- /dev/null +++ b/bindings/dotnet/UnicornEngine/Unicorn.fs @@ -0,0 +1,356 @@ +namespace UnicornEngine + +open System +open System.Collections.Generic +open System.Runtime.InteropServices +open System.Linq +open UnicornEngine.Const +open UnicornEngine.Binding + +// exported hooks +type CodeHook = delegate of Unicorn * Int64 * Int32 * Object -> unit +and BlockHook = delegate of Unicorn * Int64 * Int32 * Object -> unit +and InterruptHook = delegate of Unicorn * Int32 * Object -> unit +and MemReadHook = delegate of Unicorn * Int64 * Int32 * Object -> unit +and MemWriteHook = delegate of Unicorn * Int64 * Int32 * Int64 * Object -> unit +and EventMemHook = delegate of Unicorn * Int32 * Int64 * Int32 * Int64 * Object -> Boolean +and InHook = delegate of Unicorn * Int32 * Int32 * Object -> Int32 +and OutHook = delegate of Unicorn * Int32 * Int32 * Int32 * Object -> unit +and SyscallHook = delegate of Unicorn * Object -> unit + +// the managed unicorn engine +and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = + + // hook callback list + let _codeHooks = new List<(CodeHook * (UIntPtr * Object * Object))>() + let _blockHooks = new List<(BlockHook * (UIntPtr * Object * Object))>() + let _interruptHooks = new List<(InterruptHook * (UIntPtr * Object * Object))>() + let _memReadHooks = new List<(MemReadHook * (UIntPtr * Object * Object))>() + let _memWriteHooks = new List<(MemWriteHook * (UIntPtr * Object * Object))>() + let _memEventHooks = new Dictionary>() + let _inHooks = new List<(InHook * (UIntPtr * Object * Object))>() + let _outHooks = new List<(OutHook * (UIntPtr * Object * Object))>() + let _syscallHooks = new List<(SyscallHook * (UIntPtr * Object * Object))>() + let _disposablePointers = new List() + + let _eventMemMap = + [ + (UC_HOOK_MEM_READ_UNMAPPED, UC_MEM_READ_UNMAPPED) + (UC_HOOK_MEM_WRITE_UNMAPPED, UC_MEM_WRITE_UNMAPPED) + (UC_HOOK_MEM_FETCH_UNMAPPED, UC_MEM_FETCH_UNMAPPED) + (UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT) + (UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT) + (UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT) + ] |> dict + + let mutable _eng = [|UIntPtr.Zero|] + + let strError(errorNo: Int32) = + let errorStringPointer = binding.Strerror(errorNo) + Marshal.PtrToStringAnsi(errorStringPointer) + + let checkResult(errorCode: Int32) = + // return the exception instead of raising it in order to have a more meaningful stack trace + if errorCode <> Common.UC_ERR_OK then + let errorMessage = strError(errorCode) + Some <| UnicornEngineException(errorCode, errorMessage) + else None + + let hookDel(callbacks: List<'a * (UIntPtr * Object * Object)>) (callback: 'a)= + match callbacks |> Seq.tryFind(fun item -> match item with | (c, _) -> c = callback) with + | Some(item) -> + let (hh, _, _) = snd item + match binding.HookDel(_eng.[0], hh) |> checkResult with + | Some e -> raise e + | None -> callbacks.Remove(item) |> ignore + | None -> () + + let allocate(size: Int32) = + let mem = Marshal.AllocHGlobal(size) + _disposablePointers.Add(mem) + mem.ToPointer() + + do + // initialize event list + _eventMemMap + |> Seq.map(fun kv -> kv.Key) + |> Seq.iter (fun eventType -> _memEventHooks.Add(eventType, new List())) + + // init engine + _eng <- [|new UIntPtr(allocate(IntPtr.Size))|] + let err = binding.UcOpen(uint32 arch, uint32 mode, _eng) + if err <> Common.UC_ERR_OK then + raise(ApplicationException(String.Format("Unable to open the Unicorn Engine. Error: {0}", err))) + + new(arch, mode) = new Unicorn(arch, mode, BindingFactory.getDefault()) + + member this.MemMap(address: Int64, size: Int64, perm: Int32) = + let size = new UIntPtr(uint64 size) + match binding.MemMap(_eng.[0], uint64 address, size, uint32 perm) |> checkResult with + | Some e -> raise e | None -> () + + member this.MemMapPtr(address: Int64, size: Int64, perm: Int32, ptr: IntPtr) = + let size = new UIntPtr(uint64 size) + let ptr = new UIntPtr(ptr.ToPointer()) + match binding.MemMapPtr(_eng.[0], uint64 address, size, uint32 perm, ptr) |> checkResult with + | Some e -> raise e | None -> () + + member this.MemUnmap(address: Int64, size: Int64) = + let size = new UIntPtr(uint64 size) + match binding.MemUnmap(_eng.[0], uint64 address, size) |> checkResult with + | Some e -> raise e | None -> () + + member this.MemProtect(address: Int64, size: Int64, ?perm: Int32) = + let size = new UIntPtr(uint64 size) + let perm = defaultArg perm Common.UC_PROT_ALL + match binding.MemProtect(_eng.[0], uint64 address, size, uint32 perm) |> checkResult with + | Some e -> raise e | None -> () + + member this.MemWrite(address: Int64, value: Byte array) = + match binding.MemWrite(_eng.[0], uint64 address, value, new UIntPtr(uint32 value.Length)) |> checkResult with + | Some e -> raise e | None -> () + + member this.MemRead(address: Int64, memValue: Byte array) = + match binding.MemRead(_eng.[0], uint64 address, memValue, new UIntPtr(uint32 memValue.Length)) |> checkResult with + | Some e -> raise e | None -> () + + member this.RegWrite(regId: Int32, value: Byte array) = + match binding.RegWrite(_eng.[0], regId, value) |> checkResult with + | Some e -> raise e | None -> () + + member this.RegWrite(regId: Int32, value: Int64) = + this.RegWrite(regId, int64ToBytes value) + + member this.RegRead(regId: Int32, regValue: Byte array) = + match binding.RegRead(_eng.[0], regId, regValue) |> checkResult with + | Some e -> raise e | None -> () + + member this.RegRead(regId: Int32) = + let buffer = Array.zeroCreate 8 + this.RegRead(regId, buffer) + bytesToInt64 buffer + + member this.EmuStart(beginAddr: Int64, untilAddr: Int64, timeout: Int64, count: Int64) = + match binding.EmuStart(_eng.[0], uint64 beginAddr, uint64 untilAddr, uint64 timeout, uint64 count) |> checkResult with + | Some e -> raise e | None -> () + + member this.EmuStop() = + match binding.EmuStop(_eng.[0]) |> checkResult with + | Some e -> raise e | None -> () + + member this.Close() = + match binding.Close(_eng.[0]) |> checkResult with + | Some e -> raise e | None -> () + + member this.ArchSupported(arch: Int32) = + binding.ArchSupported(arch) + + member this.ErrNo() = + binding.Errono(_eng.[0]) + + member this.AddCodeHook(callback: CodeHook, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) = + callback.Invoke(this, addr, size, userData) + + let codeHookInternal = new CodeHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(codeHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_CODE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _codeHooks.Add(callback, (hh, userData, codeHookInternal)) + + member this.AddCodeHook(callback: CodeHook, beginAddr: Int64, endAddr: Int64) = + this.AddCodeHook(callback, null, beginAddr, endAddr) + + member this.HookDel(callback: CodeHook) = + hookDel _codeHooks callback + + member this.AddBlockHook(callback: BlockHook, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) = + callback.Invoke(this, addr, size, userData) + + let blockHookInternal = new BlockHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(blockHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_BLOCK, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _blockHooks.Add(callback, (hh, userData, blockHookInternal)) + + member this.HookDel(callback: BlockHook) = + hookDel _blockHooks callback + + member this.AddInterruptHook(callback: InterruptHook, userData: Object, hookBegin: UInt64, hookEnd : UInt64) = + let trampoline(u: IntPtr) (intNumber: Int32) (user: IntPtr) = + callback.Invoke(this, intNumber, userData) + + let interruptHookInternal = new InterruptHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(interruptHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_INTR, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, hookBegin, hookEnd) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _interruptHooks.Add(callback, (hh, userData, interruptHookInternal)) + + member this.AddInterruptHook(callback: InterruptHook) = + this.AddInterruptHook(callback, null, uint64 1, uint64 0) + + member this.HookDel(callback: InterruptHook) = + hookDel _interruptHooks callback + + member this.AddMemReadHook(callback: MemReadHook, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (_eventType: Int32) (addr: Int64) (size: Int32) (user: IntPtr) = + callback.Invoke(this, addr, size, userData) + + let memReadHookInternal = new MemReadHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(memReadHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_READ, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _memReadHooks.Add(callback, (hh, userData, memReadHookInternal)) + + member this.HookDel(callback: MemReadHook) = + hookDel _memReadHooks callback + + member this.AddMemWriteHook(callback: MemWriteHook, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (_eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) = + callback.Invoke(this, addr, size, value, userData) + + let memWriteHookInternal = new MemWriteHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(memWriteHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_WRITE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _memWriteHooks.Add(callback, (hh, userData, memWriteHookInternal)) + + member this.HookDel(callback: MemWriteHook) = + hookDel _memWriteHooks callback + + member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) = + callback.Invoke(this, eventType, addr, size, value, userData) + + // register the event if not already done + _memEventHooks.Keys + |> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0) + |> Seq.iter(fun eventFlag -> + let memEventHookInternal = new EventMemHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(memEventHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, eventFlag, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _memEventHooks.[eventFlag].Add((callback, (hh, userData, memEventHookInternal))) + ) + + member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object) = + this.AddEventMemHook(callback, eventType, userData, 1, 0) + + member this.AddEventMemHook(callback: EventMemHook, eventType: Int32) = + this.AddEventMemHook(callback, eventType, null) + + member this.HookDel(callback: EventMemHook) = + _memEventHooks.Keys + |> Seq.iter(fun eventFlag -> hookDel _memEventHooks.[eventFlag] callback) + + member this.AddInHook(callback: InHook, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (port: Int32) (size: Int32) (user: IntPtr) = + callback.Invoke(this, port, size, userData) + + let inHookInternal = new InHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(inHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_IN) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _inHooks.Add(callback, (hh, userData, inHookInternal)) + + member this.AddInHook(callback: InHook, userData: Object) = + this.AddInHook(callback, userData, 1, 0) + + member this.AddInHook(callback: InHook) = + this.AddInHook(callback, null) + + member this.HookDel(callback: InHook) = + hookDel _inHooks callback + + member this.AddOutHook(callback: OutHook, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (port: Int32) (size: Int32) (value: Int32) (user: IntPtr) = + callback.Invoke(this, port, size, value, userData) + + let outHookInternal = new OutHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(outHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_OUT) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _outHooks.Add(callback, (hh, userData, outHookInternal)) + + member this.AddOutHook(callback: OutHook, userData: Object) = + this.AddOutHook(callback, userData, 1, 0) + + member this.AddOutHook(callback: OutHook) = + this.AddOutHook(callback, null) + + member this.HookDel(callback: OutHook) = + hookDel _outHooks callback + + member this.AddSyscallHook(callback: SyscallHook, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (user: IntPtr) = + callback.Invoke(this, userData) + + let syscallHookInternal = new SyscallHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(syscallHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_SYSCALL) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _syscallHooks.Add(callback, (hh, userData, syscallHookInternal)) + + member this.AddSyscallHook(callback: SyscallHook, userData: Object) = + this.AddSyscallHook(callback, userData, 1, 0) + + member this.AddSyscallHook(callback: SyscallHook) = + this.AddSyscallHook(callback, null) + + member this.HookDel(callback: SyscallHook) = + hookDel _syscallHooks callback + + member this.Version() = + let (major, minor) = (new UIntPtr(), new UIntPtr()) + let combined = binding.Version(major, minor) + (major.ToUInt32(), minor.ToUInt32(), combined) + + abstract Dispose : Boolean -> unit + default this.Dispose(disposing: Boolean) = + if (disposing) then + // free managed resources, this is the default dispose implementation pattern + () + + _disposablePointers + |> Seq.filter(fun pointer -> pointer <> IntPtr.Zero) + |> Seq.iter Marshal.FreeHGlobal + _disposablePointers.Clear() + + member this.Dispose() = + this.Dispose(true) + GC.SuppressFinalize(this) + + override this.Finalize() = + this.Dispose(false) + + interface IDisposable with + member this.Dispose() = + this.Dispose() diff --git a/bindings/dotnet/UnicornManaged/UnicornManaged.fsproj b/bindings/dotnet/UnicornEngine/UnicornEngine.fsproj similarity index 74% rename from bindings/dotnet/UnicornManaged/UnicornManaged.fsproj rename to bindings/dotnet/UnicornEngine/UnicornEngine.fsproj index 1a66562a..8fd0d790 100644 --- a/bindings/dotnet/UnicornManaged/UnicornManaged.fsproj +++ b/bindings/dotnet/UnicornEngine/UnicornEngine.fsproj @@ -1,11 +1,13 @@  net6.0 - UnicornManaged - UnicornManaged + UnicornEngine.Unicorn + UnicornEngine Copyright © Antonio Parata 2016 https://github.com/unicorn-engine/unicorn - 2.0.0 + .NET bindings for unicorn + 2.0.2-rc1 + $(VersionSuffix) 0c21f1c1-2725-4a46-9022-1905f85822a5 true true @@ -15,6 +17,10 @@ 3 + + none + + @@ -36,4 +42,8 @@ + + + + diff --git a/bindings/dotnet/UnicornManaged/UnicornEngineException.fs b/bindings/dotnet/UnicornEngine/UnicornEngineException.fs similarity index 83% rename from bindings/dotnet/UnicornManaged/UnicornEngineException.fs rename to bindings/dotnet/UnicornEngine/UnicornEngineException.fs index fd582557..68622951 100644 --- a/bindings/dotnet/UnicornManaged/UnicornEngineException.fs +++ b/bindings/dotnet/UnicornEngine/UnicornEngineException.fs @@ -1,4 +1,4 @@ -namespace UnicornManaged +namespace UnicornEngine open System diff --git a/bindings/dotnet/UnicornManaged/Unicorn.fs b/bindings/dotnet/UnicornManaged/Unicorn.fs deleted file mode 100644 index 31decbcd..00000000 --- a/bindings/dotnet/UnicornManaged/Unicorn.fs +++ /dev/null @@ -1,342 +0,0 @@ -namespace UnicornManaged - -open System -open System.Collections.Generic -open System.Runtime.InteropServices -open System.Linq -open UnicornManaged.Const -open UnicornManaged.Binding - -// exported hooks -type CodeHook = delegate of Unicorn * Int64 * Int32 * Object -> unit -and BlockHook = delegate of Unicorn * Int64 * Int32 * Object -> unit -and InterruptHook = delegate of Unicorn * Int32 * Object -> unit -and MemReadHook = delegate of Unicorn * Int64 * Int32 * Object -> unit -and MemWriteHook = delegate of Unicorn * Int64 * Int32 * Int64 * Object -> unit -and EventMemHook = delegate of Unicorn * Int32 * Int64 * Int32 * Int64 * Object -> Boolean -and InHook = delegate of Unicorn * Int32 * Int32 * Object -> Int32 -and OutHook = delegate of Unicorn * Int32 * Int32 * Int32 * Object -> unit -and SyscallHook = delegate of Unicorn * Object -> unit - -// the managed unicorn engine -and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = - - // hook callback list - let _codeHooks = new List<(CodeHook * Object)>() - let _blockHooks = new List<(BlockHook * Object)>() - let _interruptHooks = new List<(InterruptHook * Object)>() - let _memReadHooks = new List<(MemReadHook * Object)>() - let _memWriteHooks = new List<(MemWriteHook * Object)>() - let _memEventHooks = new Dictionary>() - let _inHooks = new List<(InHook * Object)>() - let _outHooks = new List<(OutHook * Object)>() - let _syscallHooks = new List<(SyscallHook * Object)>() - let _disposablePointers = new List() - - let _eventMemMap = - [ - (UC_HOOK_MEM_READ_UNMAPPED, UC_MEM_READ_UNMAPPED) - (UC_HOOK_MEM_WRITE_UNMAPPED, UC_MEM_WRITE_UNMAPPED) - (UC_HOOK_MEM_FETCH_UNMAPPED, UC_MEM_FETCH_UNMAPPED) - (UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT) - (UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT) - (UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT) - ] |> dict - - let mutable _eng = [|UIntPtr.Zero|] - - let checkResult(errCode: Int32, errMsg: String) = - if errCode <> Common.UC_ERR_OK then raise(ApplicationException(String.Format("{0}. Error: {1}", errMsg, errCode))) - - let hookDel(callbacks: List<'a * Object>) (callback: 'a)= - // TODO: invoke the native function in order to not call the trampoline anymore - callbacks - |> Seq.tryFind(fun item -> match item with | (c, _) -> c = callback) - |> (fun k -> if k.IsSome then callbacks.Remove(k.Value) |> ignore) - - let allocate(size: Int32) = - let mem = Marshal.AllocHGlobal(size) - _disposablePointers.Add(mem) - mem.ToPointer() - - do - // initialize event list - _eventMemMap - |> Seq.map(fun kv -> kv.Key) - |> Seq.iter (fun eventType -> _memEventHooks.Add(eventType, new List())) - - // init engine - _eng <- [|new UIntPtr(allocate(IntPtr.Size))|] - let err = binding.UcOpen(uint32 arch, uint32 mode, _eng) - checkResult(err, "Unable to open the Unicorn Engine") - - new(arch, mode) = new Unicorn(arch, mode, BindingFactory.getDefault()) - - member private this.CheckResult(errorCode: Int32) = - // return the exception instead of raising it in order to have a more meaningful stack trace - if errorCode <> Common.UC_ERR_OK then - let errorMessage = this.StrError(errorCode) - Some <| UnicornEngineException(errorCode, errorMessage) - else None - - member this.MemMap(address: Int64, size: Int64, perm: Int32) = - let size = new UIntPtr(uint64 size) - match binding.MemMap(_eng.[0], uint64 address, size, uint32 perm) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.MemMapPtr(address: Int64, size: Int64, perm: Int32, ptr: IntPtr) = - let size = new UIntPtr(uint64 size) - let ptr = new UIntPtr(ptr.ToPointer()) - match binding.MemMapPtr(_eng.[0], uint64 address, size, uint32 perm, ptr) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.MemUnmap(address: Int64, size: Int64) = - let size = new UIntPtr(uint64 size) - match binding.MemUnmap(_eng.[0], uint64 address, size) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.MemProtect(address: Int64, size: Int64, ?perm: Int32) = - let size = new UIntPtr(uint64 size) - let perm = defaultArg perm Common.UC_PROT_ALL - match binding.MemProtect(_eng.[0], uint64 address, size, uint32 perm) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.MemWrite(address: Int64, value: Byte array) = - match binding.MemWrite(_eng.[0], uint64 address, value, new UIntPtr(uint32 value.Length)) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.MemRead(address: Int64, memValue: Byte array) = - match binding.MemRead(_eng.[0], uint64 address, memValue, new UIntPtr(uint32 memValue.Length)) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.RegWrite(regId: Int32, value: Byte array) = - match binding.RegWrite(_eng.[0], regId, value) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.RegWrite(regId: Int32, value: Int64) = - this.RegWrite(regId, int64ToBytes value) - - member this.RegRead(regId: Int32, regValue: Byte array) = - match binding.RegRead(_eng.[0], regId, regValue) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.RegRead(regId: Int32) = - let buffer = Array.zeroCreate 8 - this.RegRead(regId, buffer) - bytesToInt64 buffer - - member this.EmuStart(beginAddr: Int64, untilAddr: Int64, timeout: Int64, count: Int64) = - match binding.EmuStart(_eng.[0], uint64 beginAddr, uint64 untilAddr, uint64 timeout, uint64 count) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.EmuStop() = - match binding.EmuStop(_eng.[0]) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.Close() = - match binding.Close(_eng.[0]) |> this.CheckResult with - | Some e -> raise e | None -> () - - member this.ArchSupported(arch: Int32) = - binding.ArchSupported(arch) - - member this.ErrNo() = - binding.Errono(_eng.[0]) - - member this.StrError(errorNo: Int32) = - let errorStringPointer = binding.Strerror(errorNo) - Marshal.PtrToStringAnsi(errorStringPointer) - - member this.AddCodeHook(callback: CodeHook, userData: Object, beginAddr: Int64, endAddr: Int64) = - let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) = - _codeHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData)) - - if _codeHooks |> Seq.isEmpty then - let funcPointer = Marshal.GetFunctionPointerForDelegate(new CodeHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_CODE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with - | Some e -> raise e | None -> () - - _codeHooks.Add(callback, userData) - - member this.AddCodeHook(callback: CodeHook, beginAddr: Int64, endAddr: Int64) = - this.AddCodeHook(callback, null, beginAddr, endAddr) - - member this.HookDel(callback: CodeHook) = - hookDel _codeHooks callback - - member this.AddBlockHook(callback: BlockHook, userData: Object, beginAddr: Int64, endAddr: Int64) = - let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) = - _blockHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData)) - - if _blockHooks |> Seq.isEmpty then - let funcPointer = Marshal.GetFunctionPointerForDelegate(new BlockHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_BLOCK, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with - | Some e -> raise e | None -> () - - _blockHooks.Add(callback, userData) - - member this.HookDel(callback: BlockHook) = - hookDel _blockHooks callback - - member this.AddInterruptHook(callback: InterruptHook, userData: Object, hookBegin: UInt64, hookEnd : UInt64) = - let trampoline(u: IntPtr) (intNumber: Int32) (user: IntPtr) = - _interruptHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, intNumber, userData)) - - if _interruptHooks |> Seq.isEmpty then - let funcPointer = Marshal.GetFunctionPointerForDelegate(new InterruptHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_INTR, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, hookBegin, hookEnd) |> this.CheckResult with - | Some e -> raise e | None -> () - - _interruptHooks.Add(callback, userData) - - member this.AddInterruptHook(callback: InterruptHook) = - this.AddInterruptHook(callback, null, uint64 1, uint64 0) - - member this.HookDel(callback: InterruptHook) = - hookDel _interruptHooks callback - - member this.AddMemReadHook(callback: MemReadHook, userData: Object, beginAddr: Int64, endAddr: Int64) = - let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) = - _memReadHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData)) - - if _memReadHooks |> Seq.isEmpty then - let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemReadHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_READ, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with - | Some e -> raise e | None -> () - - _memReadHooks.Add(callback, userData) - - member this.HookDel(callback: MemReadHook) = - hookDel _memReadHooks callback - - member this.AddMemWriteHook(callback: MemWriteHook, userData: Object, beginAddr: Int64, endAddr: Int64) = - let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) = - _memWriteHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, value, userData)) - - if _memWriteHooks |> Seq.isEmpty then - let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemWriteHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_WRITE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with - | Some e -> raise e | None -> () - - _memWriteHooks.Add(callback, userData) - - member this.HookDel(callback: MemWriteHook) = - hookDel _memWriteHooks callback - - member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object) = - let trampoline(u: IntPtr) (eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) = - _memEventHooks.Keys - |> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0) - |> Seq.map(fun eventflag -> _memEventHooks.[eventflag]) - |> Seq.concat - |> Seq.map(fun (callback, userData) -> callback.Invoke(this, eventType, addr, size, value, userData)) - |> Seq.forall id - - // register the event if not already done - _memEventHooks.Keys - |> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0) - |> Seq.filter(fun eventFlag -> _memEventHooks.[eventFlag] |> Seq.isEmpty) - |> Seq.iter(fun eventFlag -> - let funcPointer = Marshal.GetFunctionPointerForDelegate(new EventMemHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, eventFlag, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0) |> this.CheckResult with - | Some e -> raise e | None -> () - ) - - // register the callbacks - _memEventHooks.Keys - |> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0) - |> Seq.iter(fun eventFlag -> _memEventHooks.[eventFlag].Add((callback, userData))) - - member this.AddEventMemHook(callback: EventMemHook, eventType: Int32) = - this.AddEventMemHook(callback, eventType, null) - - member this.HookDel(callback: EventMemHook) = - let callbacks = (_memEventHooks.Values |> Seq.concat).ToList() - hookDel callbacks callback - - member this.AddInHook(callback: InHook, userData: Object) = - let trampoline(u: IntPtr) (port: Int32) (size: Int32) (user: IntPtr) = - _inHooks - |> Seq.map(fun (callback, userData) -> callback.Invoke(this, port, size, userData)) - |> Seq.last - - if _inHooks |> Seq.isEmpty then - let funcPointer = Marshal.GetFunctionPointerForDelegate(new InHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_IN) |> this.CheckResult with - | Some e -> raise e | None -> () - - _inHooks.Add(callback, userData) - - member this.AddInHook(callback: InHook) = - this.AddInHook(callback, null) - - member this.AddOutHook(callback: OutHook, userData: Object) = - let trampoline(u: IntPtr) (port: Int32) (size: Int32) (value: Int32) (user: IntPtr) = - _outHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, port, size, value, userData)) - - if _outHooks |> Seq.isEmpty then - let funcPointer = Marshal.GetFunctionPointerForDelegate(new OutHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_OUT) |> this.CheckResult with - | Some e -> raise e | None -> () - - _outHooks.Add(callback, userData) - - member this.AddOutHook(callback: OutHook) = - this.AddOutHook(callback, null) - - member this.AddSyscallHook(callback: SyscallHook, userData: Object) = - let trampoline(u: IntPtr) (user: IntPtr) = - _syscallHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, userData)) - - if _syscallHooks |> Seq.isEmpty then - let funcPointer = Marshal.GetFunctionPointerForDelegate(new SyscallHookInternal(trampoline)) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_SYSCALL) |> this.CheckResult with - | Some e -> raise e | None -> () - - _syscallHooks.Add(callback, userData) - - member this.AddSyscallHook(callback: SyscallHook) = - this.AddSyscallHook(callback, null) - - member this.Version() = - let (major, minor) = (new UIntPtr(), new UIntPtr()) - let combined = binding.Version(major, minor) - (major.ToUInt32(), minor.ToUInt32(), combined) - - abstract Dispose : Boolean -> unit - default this.Dispose(disposing: Boolean) = - if (disposing) then - // free managed resources, this is the default dispose implementation pattern - () - - _disposablePointers - |> Seq.filter(fun pointer -> pointer <> IntPtr.Zero) - |> Seq.iter Marshal.FreeHGlobal - _disposablePointers.Clear() - - member this.Dispose() = - this.Dispose(true) - GC.SuppressFinalize(this) - - override this.Finalize() = - this.Dispose(false) - - interface IDisposable with - member this.Dispose() = - this.Dispose() diff --git a/bindings/dotnet/UnicornSamples/ShellcodeSample.cs b/bindings/dotnet/UnicornSamples/ShellcodeSample.cs index 7982e5e4..08ab59b1 100644 --- a/bindings/dotnet/UnicornSamples/ShellcodeSample.cs +++ b/bindings/dotnet/UnicornSamples/ShellcodeSample.cs @@ -3,8 +3,8 @@ using Gee.External.Capstone.X86; using System; using System.Diagnostics; using System.Text; -using UnicornManaged; -using UnicornManaged.Const; +using UnicornEngine; +using UnicornEngine.Const; namespace UnicornSamples { diff --git a/bindings/dotnet/UnicornSamples/UnicornSamples.csproj b/bindings/dotnet/UnicornSamples/UnicornSamples.csproj index bd603441..9aea0c7d 100644 --- a/bindings/dotnet/UnicornSamples/UnicornSamples.csproj +++ b/bindings/dotnet/UnicornSamples/UnicornSamples.csproj @@ -6,7 +6,7 @@ UnicornSamples Copyright © Antonio Parata 2016 https://github.com/unicorn-engine/unicorn - 2.0.0 + 2.0.2-rc1 {B80B5987-1E24-4309-8BF9-C4F91270F21C} true @@ -17,9 +17,9 @@ - + {0c21f1c1-2725-4a46-9022-1905f85822a5} - UnicornManaged + UnicornEngine diff --git a/bindings/dotnet/UnicornSamples/X86Sample32.cs b/bindings/dotnet/UnicornSamples/X86Sample32.cs index 24333839..bff69e79 100644 --- a/bindings/dotnet/UnicornSamples/X86Sample32.cs +++ b/bindings/dotnet/UnicornSamples/X86Sample32.cs @@ -3,8 +3,8 @@ using Gee.External.Capstone.X86; using System; using System.Diagnostics; using System.Text; -using UnicornManaged; -using UnicornManaged.Const; +using UnicornEngine; +using UnicornEngine.Const; namespace UnicornSamples { diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 19268ce5..34c97b4a 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -4,13 +4,13 @@ const ( API_MAJOR = 2 API_MINOR = 0 - API_PATCH = 1 - API_EXTRA = 255 + API_PATCH = 2 + API_EXTRA = 1 VERSION_MAJOR = 2 VERSION_MINOR = 0 - VERSION_PATCH = 1 - VERSION_EXTRA = 255 + VERSION_PATCH = 2 + VERSION_EXTRA = 1 SECOND_SCALE = 1000000 MILISECOND_SCALE = 1000 ARCH_ARM = 1 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 62759ba6..e63afb79 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -6,13 +6,13 @@ public interface UnicornConst { public static final int UC_API_MAJOR = 2; public static final int UC_API_MINOR = 0; - public static final int UC_API_PATCH = 1; - public static final int UC_API_EXTRA = 255; + public static final int UC_API_PATCH = 2; + public static final int UC_API_EXTRA = 1; public static final int UC_VERSION_MAJOR = 2; public static final int UC_VERSION_MINOR = 0; - public static final int UC_VERSION_PATCH = 1; - public static final int UC_VERSION_EXTRA = 255; + public static final int UC_VERSION_PATCH = 2; + public static final int UC_VERSION_EXTRA = 1; public static final int UC_SECOND_SCALE = 1000000; public static final int UC_MILISECOND_SCALE = 1000; public static final int UC_ARCH_ARM = 1; diff --git a/bindings/pascal/unicorn/UnicornConst.pas b/bindings/pascal/unicorn/UnicornConst.pas index 26896d13..2d75d4ae 100644 --- a/bindings/pascal/unicorn/UnicornConst.pas +++ b/bindings/pascal/unicorn/UnicornConst.pas @@ -7,13 +7,13 @@ interface const UC_API_MAJOR = 2; UC_API_MINOR = 0; - UC_API_PATCH = 1; - UC_API_EXTRA = 255; + UC_API_PATCH = 2; + UC_API_EXTRA = 1; UC_VERSION_MAJOR = 2; UC_VERSION_MINOR = 0; - UC_VERSION_PATCH = 1; - UC_VERSION_EXTRA = 255; + UC_VERSION_PATCH = 2; + UC_VERSION_EXTRA = 1; UC_SECOND_SCALE = 1000000; UC_MILISECOND_SCALE = 1000; UC_ARCH_ARM = 1; diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 8c579ad3..b8cfbdfa 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -8,6 +8,7 @@ import subprocess import shutil import sys import platform +import setuptools from distutils import log from distutils.core import setup @@ -29,7 +30,7 @@ SRC_DIR = os.path.join(ROOT_DIR, 'src') UC_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..') BUILD_DIR = os.path.join(UC_DIR, 'build_python') -VERSION = "2.0.1.post1" +VERSION = "2.0.2" if SYSTEM == 'darwin': LIBRARY_FILE = "libunicorn.2.dylib" diff --git a/bindings/python/unicorn/__init__.py b/bindings/python/unicorn/__init__.py index 9d2b717c..219de992 100644 --- a/bindings/python/unicorn/__init__.py +++ b/bindings/python/unicorn/__init__.py @@ -1,4 +1,4 @@ # Unicorn Python bindings, by Nguyen Anh Quynnh -from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const +from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const from .unicorn_const import * from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__ diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 2e6a938f..0aacfb13 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -94,7 +94,7 @@ _path_list = [os.getenv('LIBUNICORN_PATH', None), for _path in _path_list: if _path is None: continue - _uc = _load_lib(_path, _lib.get(sys.platform, "libunicorn.so")) + _uc = _load_lib(_path, _lib.get(sys.platform, "libunicorn.so.2")) if _uc is not None: break diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index f491dd26..96f2949b 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -2,13 +2,13 @@ UC_API_MAJOR = 2 UC_API_MINOR = 0 -UC_API_PATCH = 1 -UC_API_EXTRA = 255 +UC_API_PATCH = 2 +UC_API_EXTRA = 1 UC_VERSION_MAJOR = 2 UC_VERSION_MINOR = 0 -UC_VERSION_PATCH = 1 -UC_VERSION_EXTRA = 255 +UC_VERSION_PATCH = 2 +UC_VERSION_EXTRA = 1 UC_SECOND_SCALE = 1000000 UC_MILISECOND_SCALE = 1000 UC_ARCH_ARM = 1 diff --git a/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb index e317589e..6dbc46e0 100644 --- a/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb +++ b/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb @@ -4,13 +4,13 @@ module UnicornEngine UC_API_MAJOR = 2 UC_API_MINOR = 0 - UC_API_PATCH = 1 - UC_API_EXTRA = 255 + UC_API_PATCH = 2 + UC_API_EXTRA = 1 UC_VERSION_MAJOR = 2 UC_VERSION_MINOR = 0 - UC_VERSION_PATCH = 1 - UC_VERSION_EXTRA = 255 + UC_VERSION_PATCH = 2 + UC_VERSION_EXTRA = 1 UC_SECOND_SCALE = 1000000 UC_MILISECOND_SCALE = 1000 UC_ARCH_ARM = 1 diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 1f5e2251..04f5431a 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -84,6 +84,43 @@ fn build_with_cmake() { config.generator("Ninja"); } + let mut archs = String::new(); + + if std::env::var("CARGO_FEATURE_ARCH_X86").is_ok() { + archs.push_str("x86;"); + } + if std::env::var("CARGO_FEATURE_ARCH_ARM").is_ok() { + archs.push_str("arm;"); + } + if std::env::var("CARGO_FEATURE_ARCH_AARCH64").is_ok() { + archs.push_str("aarch64;"); + } + if std::env::var("CARGO_FEATURE_ARCH_RISCV").is_ok() { + archs.push_str("riscv;"); + } + if std::env::var("CARGO_FEATURE_ARCH_MIPS").is_ok() { + archs.push_str("mips;"); + } + if std::env::var("CARGO_FEATURE_ARCH_SPARC").is_ok() { + archs.push_str("sparc;"); + } + if std::env::var("CARGO_FEATURE_ARCH_M68K").is_ok() { + archs.push_str("m68k;"); + } + if std::env::var("CARGO_FEATURE_ARCH_PPC").is_ok() { + archs.push_str("ppc;"); + } + if std::env::var("CARGO_FEATURE_ARCH_S390X").is_ok() { + archs.push_str("s390x;"); + } + if std::env::var("CARGO_FEATURE_ARCH_TRICORE").is_ok() { + archs.push_str("tricore;"); + } + + if !archs.is_empty() { + archs.pop(); + } + // need to clear build target and append "build" to the path because // unicorn's CMakeLists.txt doesn't properly support 'install', so we use // the build artifacts from the build directory, which cmake crate sets @@ -91,6 +128,7 @@ fn build_with_cmake() { let dst = config .define("UNICORN_BUILD_TESTS", "OFF") .define("UNICORN_INSTALL", "OFF") + .define("UNICORN_ARCH", archs) .no_build_target(true) .build(); println!( diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index a4624a02..b1c04f57 100644 --- a/bindings/rust/src/ffi.rs +++ b/bindings/rust/src/ffi.rs @@ -1,10 +1,11 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -use crate::Unicorn; +use crate::{Unicorn, UnicornInner}; use super::unicorn_const::{uc_error, Arch, HookType, MemRegion, MemType, Mode, Query}; -use core::ffi::c_void; +use alloc::rc::Weak; +use core::{cell::UnsafeCell, ffi::c_void}; use libc::{c_char, c_int}; pub type uc_handle = *mut c_void; @@ -89,7 +90,7 @@ extern "C" { pub struct UcHook<'a, D: 'a, F: 'a> { pub callback: F, - pub uc: Unicorn<'a, D>, + pub uc: Weak>>, } pub trait IsUcHook<'a> {} @@ -106,8 +107,11 @@ where F: FnMut(&mut crate::Unicorn, u64, usize) -> u64, { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc, offset, size) + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc, offset, size) } pub extern "C" fn mmio_write_callback_proxy( @@ -120,8 +124,11 @@ pub extern "C" fn mmio_write_callback_proxy( F: FnMut(&mut crate::Unicorn, u64, usize, u64), { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc, offset, size, value); + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc, offset, size, value); } pub extern "C" fn code_hook_proxy( @@ -133,8 +140,11 @@ pub extern "C" fn code_hook_proxy( F: FnMut(&mut crate::Unicorn, u64, u32), { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc, address, size); + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc, address, size); } pub extern "C" fn block_hook_proxy( @@ -146,8 +156,11 @@ pub extern "C" fn block_hook_proxy( F: FnMut(&mut crate::Unicorn, u64, u32), { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc, address, size); + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc, address, size); } pub extern "C" fn mem_hook_proxy( @@ -162,8 +175,11 @@ where F: FnMut(&mut crate::Unicorn, MemType, u64, usize, i64) -> bool, { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc, mem_type, address, size as usize, value) + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc, mem_type, address, size as usize, value) } pub extern "C" fn intr_hook_proxy(uc: uc_handle, value: u32, user_data: *mut UcHook) @@ -171,8 +187,11 @@ where F: FnMut(&mut crate::Unicorn, u32), { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc, value); + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc, value); } pub extern "C" fn insn_in_hook_proxy( @@ -180,12 +199,16 @@ pub extern "C" fn insn_in_hook_proxy( port: u32, size: usize, user_data: *mut UcHook, -) where +) -> u32 +where F: FnMut(&mut crate::Unicorn, u32, usize) -> u32, { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc, port, size); + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc, port, size) } pub extern "C" fn insn_invalid_hook_proxy(uc: uc_handle, user_data: *mut UcHook) -> bool @@ -193,8 +216,11 @@ where F: FnMut(&mut crate::Unicorn) -> bool, { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc) + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc) } pub extern "C" fn insn_out_hook_proxy( @@ -207,8 +233,11 @@ pub extern "C" fn insn_out_hook_proxy( F: FnMut(&mut crate::Unicorn, u32, usize, u32), { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc, port, size, value); + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc, port, size, value); } pub extern "C" fn insn_sys_hook_proxy(uc: uc_handle, user_data: *mut UcHook) @@ -216,6 +245,9 @@ where F: FnMut(&mut crate::Unicorn), { let user_data = unsafe { &mut *user_data }; - debug_assert_eq!(uc, user_data.uc.get_handle()); - (user_data.callback)(&mut user_data.uc); + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + (user_data.callback)(&mut user_data_uc); } diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 7959e2d5..cb8497c7 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -369,17 +369,13 @@ impl<'a, D> Unicorn<'a, D> { let mut read_data = read_callback.map(|c| { Box::new(ffi::UcHook { callback: c, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }) }); let mut write_data = write_callback.map(|c| { Box::new(ffi::UcHook { callback: c, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }) }); @@ -388,12 +384,18 @@ impl<'a, D> Unicorn<'a, D> { self.get_handle(), address, size, - ffi::mmio_read_callback_proxy:: as _, + match read_data { + Some(_) => ffi::mmio_read_callback_proxy:: as _, + None => ptr::null_mut(), + }, match read_data { Some(ref mut d) => d.as_mut() as *mut _ as _, None => ptr::null_mut(), }, - ffi::mmio_write_callback_proxy:: as _, + match write_data { + Some(_) => ffi::mmio_write_callback_proxy:: as _, + None => ptr::null_mut(), + }, match write_data { Some(ref mut d) => d.as_mut() as *mut _ as _, None => ptr::null_mut(), @@ -586,7 +588,8 @@ impl<'a, D> Unicorn<'a, D> { return Err(uc_error::ARCH); } - let err: uc_error = unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) }; + let err: uc_error = + unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) }; if err == uc_error::OK { boxed = value.into_boxed_slice(); @@ -622,9 +625,7 @@ impl<'a, D> Unicorn<'a, D> { let mut hook_ptr = core::ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }); let err = unsafe { @@ -654,9 +655,7 @@ impl<'a, D> Unicorn<'a, D> { let mut hook_ptr = core::ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }); let err = unsafe { @@ -697,9 +696,7 @@ impl<'a, D> Unicorn<'a, D> { let mut hook_ptr = core::ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }); let err = unsafe { @@ -730,9 +727,7 @@ impl<'a, D> Unicorn<'a, D> { let mut hook_ptr = core::ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }); let err = unsafe { @@ -763,9 +758,7 @@ impl<'a, D> Unicorn<'a, D> { let mut hook_ptr = core::ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }); let err = unsafe { @@ -796,9 +789,7 @@ impl<'a, D> Unicorn<'a, D> { let mut hook_ptr = core::ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }); let err = unsafe { @@ -830,9 +821,7 @@ impl<'a, D> Unicorn<'a, D> { let mut hook_ptr = core::ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }); let err = unsafe { @@ -870,9 +859,7 @@ impl<'a, D> Unicorn<'a, D> { let mut hook_ptr = core::ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, - uc: Unicorn { - inner: self.inner.clone(), - }, + uc: Rc::downgrade(&self.inner), }); let err = unsafe { diff --git a/include/uc_priv.h b/include/uc_priv.h index 030fadce..60a9b486 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -409,7 +409,7 @@ struct uc_context { }; // check if this address is mapped in (via uc_mem_map()) -MemoryRegion *memory_mapping(struct uc_struct *uc, uint64_t address); +MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address); // We have to support 32bit system so we can't hold uint64_t on void* static inline void uc_add_exit(uc_engine *uc, uint64_t addr) @@ -486,6 +486,28 @@ static inline void hooked_regions_check(uc_engine *uc, uint64_t start, length); } +/* + break translation loop: + This is done in two cases: + 1. the user wants to stop the emulation. + 2. the user has set it IP. This requires to restart the internal + CPU emulation and rebuild some translation blocks +*/ +static inline uc_err break_translation_loop(uc_engine *uc) +{ + if (uc->emulation_done) { + return UC_ERR_OK; + } + + // TODO: make this atomic somehow? + if (uc->cpu) { + // exit the current TB + cpu_exit(uc->cpu); + } + + return UC_ERR_OK; +} + #ifdef UNICORN_TRACER #define UC_TRACE_START(loc) trace_start(get_tracer(), loc) #define UC_TRACE_END(loc, fmt, ...) \ diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 4b169d76..54ffd251 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -72,9 +72,9 @@ typedef size_t uc_hook; // Unicorn API version #define UC_API_MAJOR 2 #define UC_API_MINOR 0 -#define UC_API_PATCH 1 +#define UC_API_PATCH 2 // Release candidate version, 255 means the official release. -#define UC_API_EXTRA 255 +#define UC_API_EXTRA 1 // Unicorn package version #define UC_VERSION_MAJOR UC_API_MAJOR diff --git a/msvc/config-host.h b/msvc/config-host.h index 943d8593..a5e1e190 100644 --- a/msvc/config-host.h +++ b/msvc/config-host.h @@ -7,3 +7,10 @@ #define CONFIG_CMPXCHG128 1 // #define CONFIG_ATOMIC64 1 #define CONFIG_PLUGIN 1 + +// QEMU by default allocates (and commits) 1GB memory on Windows, and multiple Unicorn instances will result in OOM error easily. +// Unfortunately, Windows doesn't have a similar demand paging feature like mmap(), therefore a workaround is to use tcg regions mechanism. +// Note most Unicorn hacks (and even QEMU!) relies on the assumption that the translation memory won't run out and thus it might result +// in some unexpected errors. If that is case, define WIN32_QEMU_ALLOC_BUFFER to align with QEMU and Unicorn <= 2.0.1 behavior. +// +// #define WIN32_QEMU_ALLOC_BUFFER \ No newline at end of file diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 04c892a2..d591e9d1 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1436,7 +1436,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, bool handled; HOOK_FOREACH_VAR_DECLARE; struct uc_struct *uc = env->uc; - MemoryRegion *mr = memory_mapping(uc, addr); + MemoryRegion *mr = find_memory_region(uc, addr); // memory might be still unmapped while reading or fetching if (mr == NULL) { @@ -1480,7 +1480,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, if (handled) { uc->invalid_error = UC_ERR_OK; - mr = memory_mapping(uc, addr); + mr = find_memory_region(uc, addr); if (mr == NULL) { uc->invalid_error = UC_ERR_MAP; cpu_exit(uc->cpu); @@ -2010,7 +2010,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, } // Load the latest memory mapping. - mr = memory_mapping(uc, addr); + mr = find_memory_region(uc, addr); // Unicorn: callback on invalid memory if (mr == NULL) { @@ -2037,7 +2037,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, return; } else { uc->invalid_error = UC_ERR_OK; - mr = memory_mapping(uc, addr); + mr = find_memory_region(uc, addr); if (mr == NULL) { uc->invalid_error = UC_ERR_MAP; cpu_exit(uc->cpu); diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 91dd5ce7..56ddb35e 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -869,6 +869,7 @@ static inline void *alloc_code_gen_buffer(struct uc_struct *uc) return buf; } #elif defined(_WIN32) +#ifdef WIN32_QEMU_ALLOC_BUFFER static inline void *alloc_code_gen_buffer(struct uc_struct *uc) { TCGContext *tcg_ctx = uc->tcg_ctx; @@ -876,6 +877,23 @@ static inline void *alloc_code_gen_buffer(struct uc_struct *uc) return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); } +#else +static inline void *alloc_code_gen_buffer(struct uc_struct *uc) +{ + TCGContext *tcg_ctx = uc->tcg_ctx; + size_t size = tcg_ctx->code_gen_buffer_size; + + void* ptr = VirtualAlloc(NULL, size, MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + + // for prolog init + VirtualAlloc(ptr, + uc->qemu_real_host_page_size * UC_TCG_REGION_PAGES_COUNT, + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + return ptr; +} +#endif void free_code_gen_buffer(struct uc_struct *uc) { TCGContext *tcg_ctx = uc->tcg_ctx; diff --git a/qemu/include/disas/dis-asm.h b/qemu/include/disas/dis-asm.h deleted file mode 100644 index c5f9fa08..00000000 --- a/qemu/include/disas/dis-asm.h +++ /dev/null @@ -1,519 +0,0 @@ -/* Interface between the opcode library and its callers. - Written by Cygnus Support, 1993. - - The opcode library (libopcodes.a) provides instruction decoders for - a large variety of instruction sets, callable with an identical - interface, for making instruction-processing programs more independent - of the instruction set being processed. */ - -#ifndef DISAS_DIS_ASM_H -#define DISAS_DIS_ASM_H - -typedef void *PTR; -typedef uint64_t bfd_vma; -typedef int64_t bfd_signed_vma; -typedef uint8_t bfd_byte; -#define sprintf_vma(s,x) sprintf (s, "%0" PRIx64, x) -#define snprintf_vma(s,ss,x) snprintf (s, ss, "%0" PRIx64, x) - -#define BFD64 - -enum bfd_flavour { - bfd_target_unknown_flavour, - bfd_target_aout_flavour, - bfd_target_coff_flavour, - bfd_target_ecoff_flavour, - bfd_target_elf_flavour, - bfd_target_ieee_flavour, - bfd_target_nlm_flavour, - bfd_target_oasys_flavour, - bfd_target_tekhex_flavour, - bfd_target_srec_flavour, - bfd_target_ihex_flavour, - bfd_target_som_flavour, - bfd_target_os9k_flavour, - bfd_target_versados_flavour, - bfd_target_msdos_flavour, - bfd_target_evax_flavour -}; - -enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; - -enum bfd_architecture -{ - bfd_arch_unknown, /* File arch not known */ - bfd_arch_obscure, /* Arch known, not one of these */ - bfd_arch_m68k, /* Motorola 68xxx */ -#define bfd_mach_m68000 1 -#define bfd_mach_m68008 2 -#define bfd_mach_m68010 3 -#define bfd_mach_m68020 4 -#define bfd_mach_m68030 5 -#define bfd_mach_m68040 6 -#define bfd_mach_m68060 7 -#define bfd_mach_cpu32 8 -#define bfd_mach_mcf5200 9 -#define bfd_mach_mcf5206e 10 -#define bfd_mach_mcf5307 11 -#define bfd_mach_mcf5407 12 -#define bfd_mach_mcf528x 13 -#define bfd_mach_mcfv4e 14 -#define bfd_mach_mcf521x 15 -#define bfd_mach_mcf5249 16 -#define bfd_mach_mcf547x 17 -#define bfd_mach_mcf548x 18 - bfd_arch_vax, /* DEC Vax */ - bfd_arch_i960, /* Intel 960 */ - /* The order of the following is important. - lower number indicates a machine type that - only accepts a subset of the instructions - available to machines with higher numbers. - The exception is the "ca", which is - incompatible with all other machines except - "core". */ - -#define bfd_mach_i960_core 1 -#define bfd_mach_i960_ka_sa 2 -#define bfd_mach_i960_kb_sb 3 -#define bfd_mach_i960_mc 4 -#define bfd_mach_i960_xa 5 -#define bfd_mach_i960_ca 6 -#define bfd_mach_i960_jx 7 -#define bfd_mach_i960_hx 8 - - bfd_arch_a29k, /* AMD 29000 */ - bfd_arch_sparc, /* SPARC */ -#define bfd_mach_sparc 1 -/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ -#define bfd_mach_sparc_sparclet 2 -#define bfd_mach_sparc_sparclite 3 -#define bfd_mach_sparc_v8plus 4 -#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ -#define bfd_mach_sparc_sparclite_le 6 -#define bfd_mach_sparc_v9 7 -#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ -#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ -#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ -/* Nonzero if MACH has the v9 instruction set. */ -#define bfd_mach_sparc_v9_p(mach) \ - ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ - && (mach) != bfd_mach_sparc_sparclite_le) - bfd_arch_mips, /* MIPS Rxxxx */ -#define bfd_mach_mips3000 3000 -#define bfd_mach_mips3900 3900 -#define bfd_mach_mips4000 4000 -#define bfd_mach_mips4010 4010 -#define bfd_mach_mips4100 4100 -#define bfd_mach_mips4300 4300 -#define bfd_mach_mips4400 4400 -#define bfd_mach_mips4600 4600 -#define bfd_mach_mips4650 4650 -#define bfd_mach_mips5000 5000 -#define bfd_mach_mips6000 6000 -#define bfd_mach_mips8000 8000 -#define bfd_mach_mips10000 10000 -#define bfd_mach_mips16 16 - bfd_arch_i386, /* Intel 386 */ -#define bfd_mach_i386_i386 0 -#define bfd_mach_i386_i8086 1 -#define bfd_mach_i386_i386_intel_syntax 2 -#define bfd_mach_x86_64 3 -#define bfd_mach_x86_64_intel_syntax 4 - bfd_arch_we32k, /* AT&T WE32xxx */ - bfd_arch_tahoe, /* CCI/Harris Tahoe */ - bfd_arch_i860, /* Intel 860 */ - bfd_arch_romp, /* IBM ROMP PC/RT */ - bfd_arch_alliant, /* Alliant */ - bfd_arch_convex, /* Convex */ - bfd_arch_m88k, /* Motorola 88xxx */ - bfd_arch_pyramid, /* Pyramid Technology */ - bfd_arch_h8300, /* Hitachi H8/300 */ -#define bfd_mach_h8300 1 -#define bfd_mach_h8300h 2 -#define bfd_mach_h8300s 3 - bfd_arch_powerpc, /* PowerPC */ -#define bfd_mach_ppc 0 -#define bfd_mach_ppc64 1 -#define bfd_mach_ppc_403 403 -#define bfd_mach_ppc_403gc 4030 -#define bfd_mach_ppc_e500 500 -#define bfd_mach_ppc_505 505 -#define bfd_mach_ppc_601 601 -#define bfd_mach_ppc_602 602 -#define bfd_mach_ppc_603 603 -#define bfd_mach_ppc_ec603e 6031 -#define bfd_mach_ppc_604 604 -#define bfd_mach_ppc_620 620 -#define bfd_mach_ppc_630 630 -#define bfd_mach_ppc_750 750 -#define bfd_mach_ppc_860 860 -#define bfd_mach_ppc_a35 35 -#define bfd_mach_ppc_rs64ii 642 -#define bfd_mach_ppc_rs64iii 643 -#define bfd_mach_ppc_7400 7400 - bfd_arch_rs6000, /* IBM RS/6000 */ - bfd_arch_hppa, /* HP PA RISC */ -#define bfd_mach_hppa10 10 -#define bfd_mach_hppa11 11 -#define bfd_mach_hppa20 20 -#define bfd_mach_hppa20w 25 - bfd_arch_d10v, /* Mitsubishi D10V */ - bfd_arch_z8k, /* Zilog Z8000 */ -#define bfd_mach_z8001 1 -#define bfd_mach_z8002 2 - bfd_arch_h8500, /* Hitachi H8/500 */ - bfd_arch_sh, /* Hitachi SH */ -#define bfd_mach_sh 1 -#define bfd_mach_sh2 0x20 -#define bfd_mach_sh_dsp 0x2d -#define bfd_mach_sh2a 0x2a -#define bfd_mach_sh2a_nofpu 0x2b -#define bfd_mach_sh2e 0x2e -#define bfd_mach_sh3 0x30 -#define bfd_mach_sh3_nommu 0x31 -#define bfd_mach_sh3_dsp 0x3d -#define bfd_mach_sh3e 0x3e -#define bfd_mach_sh4 0x40 -#define bfd_mach_sh4_nofpu 0x41 -#define bfd_mach_sh4_nommu_nofpu 0x42 -#define bfd_mach_sh4a 0x4a -#define bfd_mach_sh4a_nofpu 0x4b -#define bfd_mach_sh4al_dsp 0x4d -#define bfd_mach_sh5 0x50 - bfd_arch_alpha, /* Dec Alpha */ -#define bfd_mach_alpha 1 -#define bfd_mach_alpha_ev4 0x10 -#define bfd_mach_alpha_ev5 0x20 -#define bfd_mach_alpha_ev6 0x30 - bfd_arch_arm, /* Advanced Risc Machines ARM */ -#define bfd_mach_arm_unknown 0 -#define bfd_mach_arm_2 1 -#define bfd_mach_arm_2a 2 -#define bfd_mach_arm_3 3 -#define bfd_mach_arm_3M 4 -#define bfd_mach_arm_4 5 -#define bfd_mach_arm_4T 6 -#define bfd_mach_arm_5 7 -#define bfd_mach_arm_5T 8 -#define bfd_mach_arm_5TE 9 -#define bfd_mach_arm_XScale 10 -#define bfd_mach_arm_ep9312 11 -#define bfd_mach_arm_iWMMXt 12 -#define bfd_mach_arm_iWMMXt2 13 - bfd_arch_ns32k, /* National Semiconductors ns32000 */ - bfd_arch_w65, /* WDC 65816 */ - bfd_arch_tic30, /* Texas Instruments TMS320C30 */ - bfd_arch_v850, /* NEC V850 */ -#define bfd_mach_v850 0 - bfd_arch_arc, /* Argonaut RISC Core */ -#define bfd_mach_arc_base 0 - bfd_arch_m32r, /* Mitsubishi M32R/D */ -#define bfd_mach_m32r 0 /* backwards compatibility */ - bfd_arch_mn10200, /* Matsushita MN10200 */ - bfd_arch_mn10300, /* Matsushita MN10300 */ - bfd_arch_cris, /* Axis CRIS */ -#define bfd_mach_cris_v0_v10 255 -#define bfd_mach_cris_v32 32 -#define bfd_mach_cris_v10_v32 1032 - bfd_arch_microblaze, /* Xilinx MicroBlaze. */ - bfd_arch_moxie, /* The Moxie core. */ - bfd_arch_ia64, /* HP/Intel ia64 */ -#define bfd_mach_ia64_elf64 64 -#define bfd_mach_ia64_elf32 32 - bfd_arch_nios2, /* Nios II */ -#define bfd_mach_nios2 0 -#define bfd_mach_nios2r1 1 -#define bfd_mach_nios2r2 2 - bfd_arch_lm32, /* Lattice Mico32 */ -#define bfd_mach_lm32 1 - bfd_arch_rx, /* Renesas RX */ -#define bfd_mach_rx 0x75 -#define bfd_mach_rx_v2 0x76 -#define bfd_mach_rx_v3 0x77 - bfd_arch_last - }; -#define bfd_mach_s390_31 31 -#define bfd_mach_s390_64 64 - -typedef struct symbol_cache_entry -{ - const char *name; - union - { - PTR p; - bfd_vma i; - } udata; -} asymbol; - -typedef int (*fprintf_function)(FILE *f, const char *fmt, ...) - GCC_FMT_ATTR(2, 3); - -enum dis_insn_type { - dis_noninsn, /* Not a valid instruction */ - dis_nonbranch, /* Not a branch instruction */ - dis_branch, /* Unconditional branch */ - dis_condbranch, /* Conditional branch */ - dis_jsr, /* Jump to subroutine */ - dis_condjsr, /* Conditional jump to subroutine */ - dis_dref, /* Data reference instruction */ - dis_dref2 /* Two data references in instruction */ -}; - -/* This struct is passed into the instruction decoding routine, - and is passed back out into each callback. The various fields are used - for conveying information from your main routine into your callbacks, - for passing information into the instruction decoders (such as the - addresses of the callback functions), or for passing information - back from the instruction decoders to their callers. - - It must be initialized before it is first passed; this can be done - by hand, or using one of the initialization macros below. */ - -typedef struct disassemble_info { - fprintf_function fprintf_func; - FILE *stream; - PTR application_data; - - /* Target description. We could replace this with a pointer to the bfd, - but that would require one. There currently isn't any such requirement - so to avoid introducing one we record these explicitly. */ - /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ - enum bfd_flavour flavour; - /* The bfd_arch value. */ - enum bfd_architecture arch; - /* The bfd_mach value. */ - unsigned long mach; - /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ - enum bfd_endian endian; - - /* An array of pointers to symbols either at the location being disassembled - or at the start of the function being disassembled. The array is sorted - so that the first symbol is intended to be the one used. The others are - present for any misc. purposes. This is not set reliably, but if it is - not NULL, it is correct. */ - asymbol **symbols; - /* Number of symbols in array. */ - int num_symbols; - - /* For use by the disassembler. - The top 16 bits are reserved for public use (and are documented here). - The bottom 16 bits are for the internal use of the disassembler. */ - unsigned long flags; -#define INSN_HAS_RELOC 0x80000000 -#define INSN_ARM_BE32 0x00010000 - PTR private_data; - - /* Function used to get bytes to disassemble. MEMADDR is the - address of the stuff to be disassembled, MYADDR is the address to - put the bytes in, and LENGTH is the number of bytes to read. - INFO is a pointer to this struct. - Returns an errno value or 0 for success. */ - int (*read_memory_func) - (bfd_vma memaddr, bfd_byte *myaddr, int length, - struct disassemble_info *info); - - /* Function which should be called if we get an error that we can't - recover from. STATUS is the errno value from read_memory_func and - MEMADDR is the address that we were trying to read. INFO is a - pointer to this struct. */ - void (*memory_error_func) - (int status, bfd_vma memaddr, struct disassemble_info *info); - - /* Function called to print ADDR. */ - void (*print_address_func) - (bfd_vma addr, struct disassemble_info *info); - - /* Function called to print an instruction. The function is architecture - * specific. - */ - int (*print_insn)(bfd_vma addr, struct disassemble_info *info); - - /* Function called to determine if there is a symbol at the given ADDR. - If there is, the function returns 1, otherwise it returns 0. - This is used by ports which support an overlay manager where - the overlay number is held in the top part of an address. In - some circumstances we want to include the overlay number in the - address, (normally because there is a symbol associated with - that address), but sometimes we want to mask out the overlay bits. */ - int (* symbol_at_address_func) - (bfd_vma addr, struct disassemble_info * info); - - /* These are for buffer_read_memory. */ - bfd_byte *buffer; - bfd_vma buffer_vma; - int buffer_length; - - /* This variable may be set by the instruction decoder. It suggests - the number of bytes objdump should display on a single line. If - the instruction decoder sets this, it should always set it to - the same value in order to get reasonable looking output. */ - int bytes_per_line; - - /* the next two variables control the way objdump displays the raw data */ - /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ - /* output will look like this: - 00: 00000000 00000000 - with the chunks displayed according to "display_endian". */ - int bytes_per_chunk; - enum bfd_endian display_endian; - - /* Results from instruction decoders. Not all decoders yet support - this information. This info is set each time an instruction is - decoded, and is only valid for the last such instruction. - - To determine whether this decoder supports this information, set - insn_info_valid to 0, decode an instruction, then check it. */ - - char insn_info_valid; /* Branch info has been set. */ - char branch_delay_insns; /* How many sequential insn's will run before - a branch takes effect. (0 = normal) */ - char data_size; /* Size of data reference in insn, in bytes */ - enum dis_insn_type insn_type; /* Type of instruction */ - bfd_vma target; /* Target address of branch or dref, if known; - zero if unknown. */ - bfd_vma target2; /* Second target address for dref2 */ - - /* Command line options specific to the target disassembler. */ - char * disassembler_options; - - /* Field intended to be used by targets in any way they deem suitable. */ - int64_t target_info; - - /* Options for Capstone disassembly. */ - int cap_arch; - int cap_mode; - int cap_insn_unit; - int cap_insn_split; - -} disassemble_info; - - -/* Standard disassemblers. Disassemble one instruction at the given - target address. Return number of bytes processed. */ -typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *); - -int print_insn_tci(bfd_vma, disassemble_info*); -int print_insn_big_mips (bfd_vma, disassemble_info*); -int print_insn_little_mips (bfd_vma, disassemble_info*); -int print_insn_nanomips (bfd_vma, disassemble_info*); -int print_insn_i386 (bfd_vma, disassemble_info*); -int print_insn_m68k (bfd_vma, disassemble_info*); -int print_insn_z8001 (bfd_vma, disassemble_info*); -int print_insn_z8002 (bfd_vma, disassemble_info*); -int print_insn_h8300 (bfd_vma, disassemble_info*); -int print_insn_h8300h (bfd_vma, disassemble_info*); -int print_insn_h8300s (bfd_vma, disassemble_info*); -int print_insn_h8500 (bfd_vma, disassemble_info*); -int print_insn_arm_a64 (bfd_vma, disassemble_info*); -int print_insn_alpha (bfd_vma, disassemble_info*); -disassembler_ftype arc_get_disassembler (int, int); -int print_insn_arm (bfd_vma, disassemble_info*); -int print_insn_sparc (bfd_vma, disassemble_info*); -int print_insn_big_a29k (bfd_vma, disassemble_info*); -int print_insn_little_a29k (bfd_vma, disassemble_info*); -int print_insn_i960 (bfd_vma, disassemble_info*); -int print_insn_sh (bfd_vma, disassemble_info*); -int print_insn_shl (bfd_vma, disassemble_info*); -int print_insn_hppa (bfd_vma, disassemble_info*); -int print_insn_m32r (bfd_vma, disassemble_info*); -int print_insn_m88k (bfd_vma, disassemble_info*); -int print_insn_mn10200 (bfd_vma, disassemble_info*); -int print_insn_mn10300 (bfd_vma, disassemble_info*); -int print_insn_moxie (bfd_vma, disassemble_info*); -int print_insn_ns32k (bfd_vma, disassemble_info*); -int print_insn_big_powerpc (bfd_vma, disassemble_info*); -int print_insn_little_powerpc (bfd_vma, disassemble_info*); -int print_insn_rs6000 (bfd_vma, disassemble_info*); -int print_insn_w65 (bfd_vma, disassemble_info*); -int print_insn_d10v (bfd_vma, disassemble_info*); -int print_insn_v850 (bfd_vma, disassemble_info*); -int print_insn_tic30 (bfd_vma, disassemble_info*); -int print_insn_ppc (bfd_vma, disassemble_info*); -int print_insn_s390 (bfd_vma, disassemble_info*); -int print_insn_crisv32 (bfd_vma, disassemble_info*); -int print_insn_crisv10 (bfd_vma, disassemble_info*); -int print_insn_microblaze (bfd_vma, disassemble_info*); -int print_insn_ia64 (bfd_vma, disassemble_info*); -int print_insn_lm32 (bfd_vma, disassemble_info*); -int print_insn_big_nios2 (bfd_vma, disassemble_info*); -int print_insn_little_nios2 (bfd_vma, disassemble_info*); -int print_insn_xtensa (bfd_vma, disassemble_info*); -int print_insn_riscv32 (bfd_vma, disassemble_info*); -int print_insn_riscv64 (bfd_vma, disassemble_info*); -int print_insn_rx(bfd_vma, disassemble_info *); - -#if 0 -/* Fetch the disassembler for a given BFD, if that support is available. */ -disassembler_ftype disassembler(bfd *); -#endif - - -/* This block of definitions is for particular callers who read instructions - into a buffer before calling the instruction decoder. */ - -/* Here is a function which callers may wish to use for read_memory_func. - It gets bytes from a buffer. */ -int buffer_read_memory(bfd_vma, bfd_byte *, int, struct disassemble_info *); - -/* This function goes with buffer_read_memory. - It prints a message using info->fprintf_func and info->stream. */ -void perror_memory(int, bfd_vma, struct disassemble_info *); - - -/* Just print the address in hex. This is included for completeness even - though both GDB and objdump provide their own (to print symbolic - addresses). */ -void generic_print_address(bfd_vma, struct disassemble_info *); - -/* Always true. */ -int generic_symbol_at_address(bfd_vma, struct disassemble_info *); - -/* Macro to initialize a disassemble_info struct. This should be called - by all applications creating such a struct. */ -#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ - (INFO).flavour = bfd_target_unknown_flavour, \ - (INFO).arch = bfd_arch_unknown, \ - (INFO).mach = 0, \ - (INFO).endian = BFD_ENDIAN_UNKNOWN, \ - INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) - -/* Call this macro to initialize only the internal variables for the - disassembler. Architecture dependent things such as byte order, or machine - variant are not touched by this macro. This makes things much easier for - GDB which must initialize these things separately. */ - -#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ - (INFO).fprintf_func = (FPRINTF_FUNC), \ - (INFO).stream = (STREAM), \ - (INFO).symbols = NULL, \ - (INFO).num_symbols = 0, \ - (INFO).private_data = NULL, \ - (INFO).buffer = NULL, \ - (INFO).buffer_vma = 0, \ - (INFO).buffer_length = 0, \ - (INFO).read_memory_func = buffer_read_memory, \ - (INFO).memory_error_func = perror_memory, \ - (INFO).print_address_func = generic_print_address, \ - (INFO).print_insn = NULL, \ - (INFO).symbol_at_address_func = generic_symbol_at_address, \ - (INFO).flags = 0, \ - (INFO).bytes_per_line = 0, \ - (INFO).bytes_per_chunk = 0, \ - (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ - (INFO).disassembler_options = NULL, \ - (INFO).insn_info_valid = 0 - -#ifndef ATTRIBUTE_UNUSED -#define ATTRIBUTE_UNUSED __attribute__((unused)) -#endif - -/* from libbfd */ - -bfd_vma bfd_getl64 (const bfd_byte *addr); -bfd_vma bfd_getl32 (const bfd_byte *addr); -bfd_vma bfd_getb32 (const bfd_byte *addr); -bfd_vma bfd_getl16 (const bfd_byte *addr); -bfd_vma bfd_getb16 (const bfd_byte *addr); -typedef bool bfd_boolean; - -#endif /* DISAS_DIS_ASM_H */ diff --git a/qemu/include/hw/core/cpu.h b/qemu/include/hw/core/cpu.h index d1b7c250..097a7f63 100644 --- a/qemu/include/hw/core/cpu.h +++ b/qemu/include/hw/core/cpu.h @@ -20,6 +20,7 @@ #ifndef QEMU_CPU_H #define QEMU_CPU_H +#include #include "exec/hwaddr.h" #include "exec/memattrs.h" #include "qemu/bitmap.h" diff --git a/qemu/include/tcg/tcg.h b/qemu/include/tcg/tcg.h index f3643fe3..1134c75c 100644 --- a/qemu/include/tcg/tcg.h +++ b/qemu/include/tcg/tcg.h @@ -35,6 +35,11 @@ #include "tcg-apple-jit.h" #include "qemu/int128.h" +// Unicorn: Default region size for win32 +#if defined(_WIN32) && !defined(WIN32_QEMU_ALLOC_BUFFER) +#define UC_TCG_REGION_PAGES_COUNT (128) // Note less pages may cause unexpected and subtle errors. +#endif + /* XXX: make safe guess about sizes */ #define MAX_OP_PER_INSTR 266 diff --git a/qemu/softmmu/cpus.c b/qemu/softmmu/cpus.c index f6b242f3..22511ac7 100644 --- a/qemu/softmmu/cpus.c +++ b/qemu/softmmu/cpus.c @@ -96,7 +96,7 @@ static int tcg_cpu_exec(struct uc_struct *uc) r = cpu_exec(uc, cpu); // quit current TB but continue emulating? - if (uc->quit_request) { + if (uc->quit_request && !uc->stop_request) { // reset stop_request uc->stop_request = false; diff --git a/qemu/target/arm/unicorn_aarch64.c b/qemu/target/arm/unicorn_aarch64.c index fec0db68..fa40330f 100644 --- a/qemu/target/arm/unicorn_aarch64.c +++ b/qemu/target/arm/unicorn_aarch64.c @@ -372,7 +372,7 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, if (regid == UC_ARM64_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); } } diff --git a/qemu/target/arm/unicorn_arm.c b/qemu/target/arm/unicorn_arm.c index bb39b348..e706b12b 100644 --- a/qemu/target/arm/unicorn_arm.c +++ b/qemu/target/arm/unicorn_arm.c @@ -515,7 +515,7 @@ int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, if (regid == UC_ARM_REG_R15) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); } } diff --git a/qemu/target/i386/translate.c b/qemu/target/i386/translate.c index b4dc56f2..2cc88f23 100644 --- a/qemu/target/i386/translate.c +++ b/qemu/target/i386/translate.c @@ -4816,7 +4816,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) } // Sync PC in advance - gen_jmp_im(s, pc_start); + gen_jmp_im(s, pc_start - s->cs_base); // save the last operand prev_op = tcg_last_op(tcg_ctx); @@ -9314,7 +9314,7 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) DisasContext *dc = container_of(dcbase, DisasContext, base); TCGContext *tcg_ctx = dc->uc->tcg_ctx; - dc->prev_pc = dc->base.pc_next; + dc->prev_pc = dc->base.pc_next - dc->cs_base; tcg_gen_insn_start(tcg_ctx, dc->base.pc_next, dc->cc_op); } diff --git a/qemu/target/i386/unicorn.c b/qemu/target/i386/unicorn.c index f10b70e2..3e83b0ba 100644 --- a/qemu/target/i386/unicorn.c +++ b/qemu/target/i386/unicorn.c @@ -69,17 +69,6 @@ void x86_reg_reset(struct uc_struct *uc) { CPUArchState *env = uc->cpu->env_ptr; - env->features[FEAT_1_EDX] = CPUID_CX8 | CPUID_CMOV | CPUID_SSE2 | - CPUID_FXSR | CPUID_SSE | CPUID_CLFLUSH; - env->features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 | - CPUID_EXT_SSE42 | CPUID_EXT_AES | - CPUID_EXT_CX16; - env->features[FEAT_8000_0001_EDX] = CPUID_EXT2_3DNOW | CPUID_EXT2_RDTSCP; - env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | - CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG; - env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | - CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP; - memset(env->regs, 0, sizeof(env->regs)); memset(env->segs, 0, sizeof(env->segs)); memset(env->cr, 0, sizeof(env->cr)); @@ -1532,7 +1521,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, case UC_X86_REG_IP: // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); break; } @@ -1546,7 +1535,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, case UC_X86_REG_IP: // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); break; } #endif diff --git a/qemu/target/m68k/unicorn.c b/qemu/target/m68k/unicorn.c index d748ace7..d0a091fa 100644 --- a/qemu/target/m68k/unicorn.c +++ b/qemu/target/m68k/unicorn.c @@ -117,7 +117,7 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, if (regid == UC_M68K_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); } } diff --git a/qemu/target/mips/unicorn.c b/qemu/target/mips/unicorn.c index bd4d5595..792fb45e 100644 --- a/qemu/target/mips/unicorn.c +++ b/qemu/target/mips/unicorn.c @@ -170,7 +170,7 @@ int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, if (regid == UC_MIPS_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); } } diff --git a/qemu/target/ppc/translate_init.inc.c b/qemu/target/ppc/translate_init.inc.c index a2d5c587..caef69be 100644 --- a/qemu/target/ppc/translate_init.inc.c +++ b/qemu/target/ppc/translate_init.inc.c @@ -27,7 +27,6 @@ #include "mmu-book3s-v3.h" #include "qemu/cutils.h" #include "fpu/softfloat.h" -#include "disas/dis-asm.h" /* * Generic callbacks: @@ -3456,7 +3455,6 @@ POWERPC_FAMILY(401)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -3511,7 +3509,6 @@ POWERPC_FAMILY(401x2)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -3564,7 +3561,6 @@ POWERPC_FAMILY(401x3)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -3620,7 +3616,6 @@ POWERPC_FAMILY(IOP480)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -3666,7 +3661,6 @@ POWERPC_FAMILY(403)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_PX | POWERPC_FLAG_BUS_CLK; } @@ -3730,7 +3724,6 @@ POWERPC_FAMILY(403GCX)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_PX | POWERPC_FLAG_BUS_CLK; } @@ -3794,7 +3787,6 @@ POWERPC_FAMILY(405)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_4xx; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_405; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -3896,7 +3888,6 @@ POWERPC_FAMILY(440EP)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -3933,7 +3924,6 @@ POWERPC_FAMILY(460EX)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -4015,7 +4005,6 @@ POWERPC_FAMILY(440GP)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -4098,7 +4087,6 @@ POWERPC_FAMILY(440x4)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -4198,7 +4186,6 @@ POWERPC_FAMILY(440x5)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -4235,7 +4222,6 @@ POWERPC_FAMILY(440x5wDFPU)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_403; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } @@ -4279,7 +4265,6 @@ POWERPC_FAMILY(MPC5xx)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_603; pcc->bus_model = PPC_FLAGS_INPUT_RCPU; - pcc->bfd_mach = bfd_mach_ppc_505; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } @@ -4323,7 +4308,6 @@ POWERPC_FAMILY(MPC8xx)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_MPC8xx; pcc->excp_model = POWERPC_EXCP_603; pcc->bus_model = PPC_FLAGS_INPUT_RCPU; - pcc->bfd_mach = bfd_mach_ppc_860; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } @@ -4404,7 +4388,6 @@ POWERPC_FAMILY(G2)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_G2; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_ec603e; pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } @@ -4485,7 +4468,6 @@ POWERPC_FAMILY(G2LE)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_G2; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_ec603e; pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } @@ -4637,7 +4619,6 @@ POWERPC_FAMILY(e200)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_860; pcc->flags = POWERPC_FLAG_SPE | POWERPC_FLAG_CE | POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; @@ -4737,7 +4718,6 @@ POWERPC_FAMILY(e300)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_603; pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } @@ -5024,7 +5004,6 @@ POWERPC_FAMILY(e500v1)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_860; pcc->flags = POWERPC_FLAG_SPE | POWERPC_FLAG_CE | POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; @@ -5071,7 +5050,6 @@ POWERPC_FAMILY(e500v2)(CPUClass *oc, void *data) #endif pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_860; pcc->flags = POWERPC_FLAG_SPE | POWERPC_FLAG_CE | POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; @@ -5116,7 +5094,6 @@ POWERPC_FAMILY(e500mc)(CPUClass *oc, void *data) pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; /* FIXME: figure out the correct flag for e500mc */ - pcc->bfd_mach = bfd_mach_ppc_e500; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -5164,7 +5141,6 @@ POWERPC_FAMILY(e5500)(CPUClass *oc, void *data) pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; /* FIXME: figure out the correct flag for e5500 */ - pcc->bfd_mach = bfd_mach_ppc_e500; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -5211,7 +5187,6 @@ POWERPC_FAMILY(e6500)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; - pcc->bfd_mach = bfd_mach_ppc_e500; pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_VRE; } @@ -5287,7 +5262,6 @@ POWERPC_FAMILY(601)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_601; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_601; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; } @@ -5328,7 +5302,6 @@ POWERPC_FAMILY(601v)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_601; pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_601; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; } @@ -5396,7 +5369,6 @@ POWERPC_FAMILY(602)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_602; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_602; pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } @@ -5462,7 +5434,6 @@ POWERPC_FAMILY(603)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_603; pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } @@ -5528,7 +5499,6 @@ POWERPC_FAMILY(603E)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603E; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_ec603e; pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } @@ -5589,7 +5559,6 @@ POWERPC_FAMILY(604)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_604; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_604; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -5670,7 +5639,6 @@ POWERPC_FAMILY(604E)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_604; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_604; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -5738,7 +5706,6 @@ POWERPC_FAMILY(740)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_750; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -5815,7 +5782,6 @@ POWERPC_FAMILY(750)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_750; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -6015,7 +5981,6 @@ POWERPC_FAMILY(750cl)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_750; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -6095,7 +6060,6 @@ POWERPC_FAMILY(750cx)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_750; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -6180,7 +6144,6 @@ POWERPC_FAMILY(750fx)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_750; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -6265,7 +6228,6 @@ POWERPC_FAMILY(750gx)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_7x0; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_750; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -6340,7 +6302,6 @@ POWERPC_FAMILY(745)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_7x5; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_750; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -6426,7 +6387,6 @@ POWERPC_FAMILY(755)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_7x5; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_750; pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } @@ -6501,7 +6461,6 @@ POWERPC_FAMILY(7400)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_7400; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -6583,7 +6542,6 @@ POWERPC_FAMILY(7410)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_7400; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -6690,7 +6648,6 @@ POWERPC_FAMILY(7440)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_7400; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -6823,7 +6780,6 @@ POWERPC_FAMILY(7450)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_7400; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -6959,7 +6915,6 @@ POWERPC_FAMILY(7445)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_7400; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -7097,7 +7052,6 @@ POWERPC_FAMILY(7455)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_7400; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -7260,7 +7214,6 @@ POWERPC_FAMILY(7457)(CPUClass *oc, void *data) pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_7400; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -7400,7 +7353,6 @@ POWERPC_FAMILY(e600)(CPUClass *oc, void *data) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_7400; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -8264,7 +8216,6 @@ POWERPC_FAMILY(970)(CPUClass *oc, void *data) pcc->hash64_opts = &ppc_hash64_opts_basic; pcc->excp_model = POWERPC_EXCP_970; pcc->bus_model = PPC_FLAGS_INPUT_970; - pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -8340,7 +8291,6 @@ POWERPC_FAMILY(POWER5P)(CPUClass *oc, void *data) pcc->lrg_decr_bits = 32; pcc->excp_model = POWERPC_EXCP_970; pcc->bus_model = PPC_FLAGS_INPUT_970; - pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; @@ -8481,7 +8431,6 @@ POWERPC_FAMILY(POWER7)(CPUClass *oc, void *data) pcc->lrg_decr_bits = 32; pcc->excp_model = POWERPC_EXCP_POWER7; pcc->bus_model = PPC_FLAGS_INPUT_POWER7; - pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | @@ -8656,7 +8605,6 @@ POWERPC_FAMILY(POWER8)(CPUClass *oc, void *data) pcc->n_host_threads = 8; pcc->excp_model = POWERPC_EXCP_POWER8; pcc->bus_model = PPC_FLAGS_INPUT_POWER7; - pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | @@ -8869,7 +8817,6 @@ POWERPC_FAMILY(POWER9)(CPUClass *oc, void *data) pcc->n_host_threads = 4; pcc->excp_model = POWERPC_EXCP_POWER9; pcc->bus_model = PPC_FLAGS_INPUT_POWER9; - pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | @@ -9080,7 +9027,6 @@ POWERPC_FAMILY(POWER10)(CPUClass *oc, void *data) pcc->lrg_decr_bits = 56; pcc->excp_model = POWERPC_EXCP_POWER9; pcc->bus_model = PPC_FLAGS_INPUT_POWER9; - pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | @@ -10257,7 +10203,6 @@ static void ppc_cpu_instance_init(struct uc_struct *uc, CPUState *obj) env->insns_flags = pcc->insns_flags; env->insns_flags2 = pcc->insns_flags2; env->flags = pcc->flags; - env->bfd_mach = pcc->bfd_mach; env->check_pow = pcc->check_pow; /* @@ -10290,74 +10235,12 @@ static bool ppc_pvr_match_default(PowerPCCPUClass *pcc, uint32_t pvr) return pcc->pvr == pvr; } -#if 0 -static gchar *ppc_gdb_arch_name(CPUState *cs) -{ -#if defined(TARGET_PPC64) - return g_strdup("powerpc:common64"); -#else - return g_strdup("powerpc:common"); -#endif -} - -static void ppc_disas_set_info(CPUState *cs, disassemble_info *info) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - if ((env->hflags >> MSR_LE) & 1) { - info->endian = BFD_ENDIAN_LITTLE; - } - info->mach = env->bfd_mach; - if (!env->bfd_mach) { -#ifdef TARGET_PPC64 - info->mach = bfd_mach_ppc64; -#else - info->mach = bfd_mach_ppc; -#endif - } - info->disassembler_options = (char *)"any"; - info->print_insn = print_insn_ppc; - - info->cap_arch = CS_ARCH_PPC; -#ifdef TARGET_PPC64 - info->cap_mode = CS_MODE_64; -#endif -} - -static Property ppc_cpu_properties[] = { - DEFINE_PROP_BOOL("pre-2.8-migration", PowerPCCPU, pre_2_8_migration, false), - DEFINE_PROP_BOOL("pre-2.10-migration", PowerPCCPU, pre_2_10_migration, - false), - DEFINE_PROP_BOOL("pre-3.0-migration", PowerPCCPU, pre_3_0_migration, - false), - DEFINE_PROP_END_OF_LIST(), -}; -#endif - static void ppc_cpu_class_init(struct uc_struct *uc, CPUClass *oc) { PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); -#if 0 - DeviceClass *dc = DEVICE_CLASS(oc); - - device_class_set_parent_realize(dc, ppc_cpu_realize, - &pcc->parent_realize); - device_class_set_parent_unrealize(dc, ppc_cpu_unrealize, - &pcc->parent_unrealize); -#endif pcc->pvr_match = ppc_pvr_match_default; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_always; -#if 0 - device_class_set_props(dc, ppc_cpu_properties); - - device_class_set_parent_reset(dc, ppc_cpu_reset, &pcc->parent_reset); - - cc->class_by_name = ppc_cpu_class_by_name; - pcc->parent_parse_features = cc->parse_features; - cc->parse_features = ppc_cpu_parse_featurestr; -#endif /* parent class is CPUClass, parent_reset() is cpu_common_reset(). */ pcc->parent_reset = cc->reset; /* overwrite the CPUClass->reset to arch reset: arm_cpu_reset(). */ @@ -10366,47 +10249,13 @@ static void ppc_cpu_class_init(struct uc_struct *uc, CPUClass *oc) cc->has_work = ppc_cpu_has_work; cc->do_interrupt = ppc_cpu_do_interrupt; cc->cpu_exec_interrupt = ppc_cpu_exec_interrupt; -#if 0 - cc->dump_state = ppc_cpu_dump_state; - cc->dump_statistics = ppc_cpu_dump_statistics; -#endif cc->set_pc = ppc_cpu_set_pc; -#if 0 - cc->gdb_read_register = ppc_cpu_gdb_read_register; - cc->gdb_write_register = ppc_cpu_gdb_write_register; -#endif cc->do_unaligned_access = ppc_cpu_do_unaligned_access; cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug; -#if 0 - cc->vmsd = &vmstate_ppc_cpu; - cc->write_elf64_note = ppc64_cpu_write_elf64_note; - cc->write_elf32_note = ppc32_cpu_write_elf32_note; - - cc->gdb_num_core_regs = 71; - cc->gdb_get_dynamic_xml = ppc_gdb_get_dynamic_xml; -#ifdef USE_APPLE_GDB - cc->gdb_read_register = ppc_cpu_gdb_read_register_apple; - cc->gdb_write_register = ppc_cpu_gdb_write_register_apple; - cc->gdb_num_core_regs = 71 + 32; -#endif - - cc->gdb_arch_name = ppc_gdb_arch_name; -#if defined(TARGET_PPC64) - cc->gdb_core_xml_file = "power64-core.xml"; -#else - cc->gdb_core_xml_file = "power-core.xml"; -#endif - cc->virtio_is_big_endian = ppc_cpu_is_big_endian; -#endif cc->tcg_initialize = ppc_translate_init; cc->tlb_fill = ppc_cpu_tlb_fill; cc->cpu_exec_enter = ppc_cpu_exec_enter; cc->cpu_exec_exit = ppc_cpu_exec_exit; - -#if 0 - cc->disas_set_info = ppc_disas_set_info; - dc->fw_name = "PowerPC,UNKNOWN"; -#endif } /* PowerPC CPU definitions from cpu-models.c*/ diff --git a/qemu/target/ppc/unicorn.c b/qemu/target/ppc/unicorn.c index b157ce5a..fc8e24f1 100644 --- a/qemu/target/ppc/unicorn.c +++ b/qemu/target/ppc/unicorn.c @@ -361,7 +361,7 @@ int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, if (regid == UC_PPC_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); } } diff --git a/qemu/target/riscv/unicorn.c b/qemu/target/riscv/unicorn.c index a440a6bd..8970051e 100644 --- a/qemu/target/riscv/unicorn.c +++ b/qemu/target/riscv/unicorn.c @@ -560,7 +560,7 @@ int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, if (regid == UC_RISCV_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); } } diff --git a/qemu/target/s390x/unicorn.c b/qemu/target/s390x/unicorn.c index 469cda7c..6378fe4c 100644 --- a/qemu/target/s390x/unicorn.c +++ b/qemu/target/s390x/unicorn.c @@ -130,7 +130,7 @@ static int s390_reg_write(struct uc_struct *uc, unsigned int *regs, if (regid == UC_S390X_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); } } diff --git a/qemu/target/tricore/unicorn.c b/qemu/target/tricore/unicorn.c index 88e937bb..a3eac632 100644 --- a/qemu/target/tricore/unicorn.c +++ b/qemu/target/tricore/unicorn.c @@ -229,7 +229,7 @@ int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, if (regid == UC_TRICORE_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); + break_translation_loop(uc); } } diff --git a/qemu/tcg/i386/tcg-target.inc.c b/qemu/tcg/i386/tcg-target.inc.c index 260de96c..fc5cdbba 100644 --- a/qemu/tcg/i386/tcg-target.inc.c +++ b/qemu/tcg/i386/tcg-target.inc.c @@ -24,6 +24,10 @@ #include "../tcg-pool.inc.c" +#ifdef _MSC_VER +#include +#endif + #ifdef CONFIG_DEBUG_TCG static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { #if TCG_TARGET_REG_BITS == 64 @@ -3768,11 +3772,6 @@ static void tcg_target_init(TCGContext *s) have_movbe = (c & bit_MOVBE) != 0; have_popcnt = (c & bit_POPCNT) != 0; -#ifdef _MSC_VER - // FIXME: detect AVX1 & AVX2: https://gist.github.com/hi2p-perim/7855506 - have_avx1 = true; - have_avx2 = true; -#else /* There are a number of things we must check before we can be sure of not hitting invalid opcode. */ if (c & bit_OSXSAVE) { @@ -3780,13 +3779,18 @@ static void tcg_target_init(TCGContext *s) /* The xgetbv instruction is not available to older versions of * the assembler, so we encode the instruction manually. */ +#ifndef _MSC_VER asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcrl), "=d" (xcrh) : "c" (0)); +#else + unsigned long long bv = _xgetbv(0); + xcrl = bv & 0xFFFFFFFF; + xcrh = (bv >> 32) & 0xFFFFFFFF; +#endif if ((xcrl & 6) == 6) { have_avx1 = (c & bit_AVX) != 0; have_avx2 = (b7 & bit_AVX2) != 0; } } -#endif } #ifdef _MSC_VER diff --git a/qemu/tcg/tcg.c b/qemu/tcg/tcg.c index 4910c67c..cb76f31a 100644 --- a/qemu/tcg/tcg.c +++ b/qemu/tcg/tcg.c @@ -23,6 +23,8 @@ */ /* define it to use liveness analysis (better code) */ +#include "tcg/tcg.h" +#include #define USE_TCG_OPTIMIZATIONS #include "qemu/osdep.h" @@ -406,6 +408,13 @@ static void tcg_region_assign(TCGContext *s, size_t curr_region) s->code_gen_buffer = start; s->code_gen_ptr = start; s->code_gen_buffer_size = (char *)end - (char *)start; +#if defined(WIN32) && !defined(WIN32_QEMU_ALLOC_BUFFER) + VirtualAlloc( + s->code_gen_buffer, + ROUND_UP(s->code_gen_buffer_size, s->uc->qemu_real_host_page_size), + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); +#endif memset(s->code_gen_buffer, 0x00, s->code_gen_buffer_size); s->code_gen_highwater = (char *)end - TCG_HIGHWATER; } @@ -500,7 +509,11 @@ void tcg_region_init(TCGContext *tcg_ctx) size_t n_regions; size_t i; +#if defined(WIN32) && !defined(WIN32_QEMU_ALLOC_BUFFER) + n_regions = size / (tcg_ctx->uc->qemu_real_host_page_size * UC_TCG_REGION_PAGES_COUNT); +#else n_regions = 1; +#endif /* The first region will be 'aligned - buf' bytes larger than the others */ aligned = (void *)QEMU_ALIGN_PTR_UP(buf, page_size); @@ -537,6 +550,11 @@ void tcg_region_init(TCGContext *tcg_ctx) } tcg_ctx->tree = g_tree_new(tb_tc_cmp); + +#if defined(WIN32) && !defined(WIN32_QEMU_ALLOC_BUFFER) + // Allocate a region immediately, or the highwater is not set correctly. + tcg_region_alloc(tcg_ctx); +#endif } /* diff --git a/tests/unit/test_ctl.c b/tests/unit/test_ctl.c index 05f4c54e..e1e467d3 100644 --- a/tests/unit/test_ctl.c +++ b/tests/unit/test_ctl.c @@ -304,6 +304,40 @@ static void test_uc_hook_cached_uaf(void) #endif } +static void test_uc_emu_stop_set_ip_callback(uc_engine *uc, uint64_t address, uint32_t size, void *userdata) +{ + uint64_t rip = code_start + 0xb; + + if (address == code_start + 0x7) { + uc_emu_stop(uc); + uc_reg_write(uc, UC_X86_REG_RIP, &rip); + } +} + +static void test_uc_emu_stop_set_ip(void) +{ + uc_engine *uc; + uc_hook h; + uint64_t rip; + + char code[] = "\x48\x31\xc0" // 0x0 xor rax, rax : rax = 0 + "\x90" // 0x3 nop : + "\x48\xff\xc0" // 0x4 inc rax : rax++ + "\x90" // 0x7 nop : <-- going to stop here + "\x48\xff\xc0" // 0x8 inc rax : rax++ + "\x90" // 0xb nop : + "\x0f\x0b" // 0xc ud2 : <-- will raise UC_ERR_INSN_INVALID, but should not never be reached + "\x90" // 0xe nop : + "\x90"; // 0xf nop : + + uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1); + OK(uc_hook_add(uc, &h, UC_HOOK_CODE, test_uc_emu_stop_set_ip_callback, NULL, 1, 0)); + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + OK(uc_reg_read(uc, UC_X86_REG_RIP, &rip)); + TEST_CHECK(rip == code_start + 0xb); + OK(uc_close(uc)); +} + TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode}, {"test_uc_ctl_page_size", test_uc_ctl_page_size}, {"test_uc_ctl_arch", test_uc_ctl_arch}, @@ -315,4 +349,5 @@ TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode}, {"test_uc_ctl_arm_cpu", test_uc_ctl_arm_cpu}, #endif {"test_uc_hook_cached_uaf", test_uc_hook_cached_uaf}, + {"test_uc_emu_stop_set_ip", test_uc_emu_stop_set_ip}, {NULL, NULL}}; diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index ddc84710..110e4b41 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1229,6 +1229,36 @@ static void test_x86_lazy_mapping(void) OK(uc_close(uc)); } +static void test_x86_16_incorrect_ip_cb(uc_engine *uc, uint64_t address, uint32_t size, void* data) +{ + uint16_t cs, ip; + + OK(uc_reg_read(uc, UC_X86_REG_CS, &cs)); + OK(uc_reg_read(uc, UC_X86_REG_IP, &ip)); + + TEST_CHECK(cs == 0x20); + TEST_CHECK(address == ((cs << 4) + ip)); +} + +static void test_x86_16_incorrect_ip(void) +{ + uc_engine *uc; + uc_hook hk1, hk2; + uint16_t cs = 0x20; + char code[] = "\x41"; // INC cx; + + uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_16, code, sizeof(code) - 1); + + OK(uc_hook_add(uc, &hk1, UC_HOOK_BLOCK, test_x86_16_incorrect_ip_cb, NULL, 1, 0)); + OK(uc_hook_add(uc, &hk2, UC_HOOK_CODE, test_x86_16_incorrect_ip_cb, NULL, 1, 0)); + + OK(uc_reg_write(uc, UC_X86_REG_CS, &cs)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_close(uc)); +} + TEST_LIST = { {"test_x86_in", test_x86_in}, {"test_x86_out", test_x86_out}, @@ -1271,4 +1301,5 @@ TEST_LIST = { {"test_x86_unaligned_access", test_x86_unaligned_access}, #endif {"test_x86_lazy_mapping", test_x86_lazy_mapping}, + {"test_x86_16_incorrect_ip", test_x86_16_incorrect_ip}, {NULL, NULL}}; diff --git a/uc.c b/uc.c index 667f40ca..a1a71366 100644 --- a/uc.c +++ b/uc.c @@ -552,7 +552,7 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size) size_t count = 0, len; while (count < size) { - MemoryRegion *mr = memory_mapping(uc, address); + MemoryRegion *mr = find_memory_region(uc, address); if (mr) { len = (size_t)MIN(size - count, mr->end - address); count += len; @@ -587,7 +587,7 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size) // memory area can overlap adjacent memory blocks while (count < size) { - MemoryRegion *mr = memory_mapping(uc, address); + MemoryRegion *mr = find_memory_region(uc, address); if (mr) { len = (size_t)MIN(size - count, mr->end - address); if (uc->read_mem(&uc->address_space_memory, address, bytes, len) == @@ -632,7 +632,7 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, // memory area can overlap adjacent memory blocks while (count < size) { - MemoryRegion *mr = memory_mapping(uc, address); + MemoryRegion *mr = find_memory_region(uc, address); if (mr) { uint32_t operms = mr->perms; if (!(operms & UC_PROT_WRITE)) { // write protected @@ -907,19 +907,8 @@ UNICORN_EXPORT uc_err uc_emu_stop(uc_engine *uc) { UC_INIT(uc); - - if (uc->emulation_done) { - return UC_ERR_OK; - } - uc->stop_request = true; - // TODO: make this atomic somehow? - if (uc->cpu) { - // exit the current TB - cpu_exit(uc->cpu); - } - - return UC_ERR_OK; + return break_translation_loop(uc); } // return target index where a memory region at the address exists, or could be @@ -976,8 +965,7 @@ static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size) } // common setup/error checking shared between uc_mem_map and uc_mem_map_ptr -static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, - uint32_t perms, MemoryRegion *block) +static uc_err mem_map(uc_engine *uc, MemoryRegion *block) { MemoryRegion **regions; int pos; @@ -1060,8 +1048,7 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) return res; } - return mem_map(uc, address, size, perms, - uc->memory_map(uc, address, size, perms)); + return mem_map(uc, uc->memory_map(uc, address, size, perms)); } UNICORN_EXPORT @@ -1085,8 +1072,7 @@ uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, return res; } - return mem_map(uc, address, size, UC_PROT_ALL, - uc->memory_map_ptr(uc, address, size, perms, ptr)); + return mem_map(uc, uc->memory_map_ptr(uc, address, size, perms, ptr)); } UNICORN_EXPORT @@ -1108,9 +1094,8 @@ uc_err uc_mmio_map(uc_engine *uc, uint64_t address, size_t size, // The callbacks do not need to be checked for NULL here, as their presence // (or lack thereof) will determine the permissions used. - return mem_map(uc, address, size, UC_PROT_NONE, - uc->memory_map_io(uc, address, size, read_cb, write_cb, - user_data_read, user_data_write)); + return mem_map(uc, uc->memory_map_io(uc, address, size, read_cb, write_cb, + user_data_read, user_data_write)); } // Create a backup copy of the indicated MemoryRegion. @@ -1254,14 +1239,7 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, // Find the correct and large enough (which contains our target mr) // to create the content backup. - QLIST_FOREACH(block, &uc->ram_list.blocks, next) - { - // block->offset is the offset within ram_addr_t, not GPA - if (block->mr->addr <= mr->addr && - block->used_length + block->mr->addr >= mr->end) { - break; - } - } + block = mr->ram_block; if (block == NULL) { return false; @@ -1423,14 +1401,14 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, addr = address; count = 0; while (count < size) { - mr = memory_mapping(uc, addr); + mr = find_memory_region(uc, addr); len = (size_t)MIN(size - count, mr->end - addr); if (mr->ram) { if (!split_region(uc, mr, addr, len, false)) { return UC_ERR_NOMEM; } - mr = memory_mapping(uc, addr); + mr = find_memory_region(uc, addr); // will this remove EXEC permission? if (((mr->perms & UC_PROT_EXEC) != 0) && ((perms & UC_PROT_EXEC) == 0)) { @@ -1444,7 +1422,7 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, return UC_ERR_NOMEM; } - mr = memory_mapping(uc, addr); + mr = find_memory_region(uc, addr); mr->perms = perms; } @@ -1503,7 +1481,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) addr = address; count = 0; while (count < size) { - mr = memory_mapping(uc, addr); + mr = find_memory_region(uc, addr); len = (size_t)MIN(size - count, mr->end - addr); if (!mr->ram) { if (!split_mmio_region(uc, mr, addr, len, true)) { @@ -1517,7 +1495,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) // if we can retrieve the mapping, then no splitting took place // so unmap here - mr = memory_mapping(uc, addr); + mr = find_memory_region(uc, addr); if (mr != NULL) { uc->memory_unmap(uc, mr); } @@ -1529,7 +1507,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) } // find the memory region of this address -MemoryRegion *memory_mapping(struct uc_struct *uc, uint64_t address) +MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address) { unsigned int i; @@ -1544,16 +1522,20 @@ MemoryRegion *memory_mapping(struct uc_struct *uc, uint64_t address) // try with the cache index first i = uc->mapped_block_cache_index; - if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr && - address < uc->mapped_blocks[i]->end) { + if (i < uc->mapped_block_count && + address >= uc->mapped_blocks[i]->addr && + address <= uc->mapped_blocks[i]->end - 1) { return uc->mapped_blocks[i]; } i = bsearch_mapped_blocks(uc, address); - if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr && - address <= uc->mapped_blocks[i]->end - 1) + if (i < uc->mapped_block_count && + address >= uc->mapped_blocks[i]->addr && + address <= uc->mapped_blocks[i]->end - 1) { + uc->mapped_block_cache_index = i; return uc->mapped_blocks[i]; + } // not found return NULL; @@ -2431,4 +2413,4 @@ void trace_end(uc_tracer *tracer, trace_loc loc, const char *fmt, ...) fprintf(stderr, "%.6fus\n", (double)(end - tracer->starts[loc]) / (double)(1000)); } -#endif \ No newline at end of file +#endif