Merge branch 'dev'
This commit is contained in:
commit
3c53a64e30
|
@ -46,6 +46,12 @@ jobs:
|
|||
python-ver: '3.8',
|
||||
name: 'manylinux2014_i686'
|
||||
}
|
||||
- {
|
||||
os: ubuntu-latest,
|
||||
arch: aarch64,
|
||||
python-ver: '3.8',
|
||||
name: 'manylinux2014_aarch64'
|
||||
}
|
||||
- {
|
||||
os: ubuntu-latest,
|
||||
arch: x64,
|
||||
|
@ -104,6 +110,10 @@ jobs:
|
|||
docker run --rm -v `pwd`/:/work dockcross/manylinux2014-x86 > ./dockcross
|
||||
chmod +x ./dockcross
|
||||
./dockcross bindings/python/build_wheel.sh
|
||||
elif [ ${{ matrix.config.name }} == 'manylinux2014_aarch64' ]; then
|
||||
docker run --rm -v `pwd`/:/work dockcross/manylinux2014-aarch64 > ./dockcross
|
||||
chmod +x ./dockcross
|
||||
./dockcross bindings/python/build_wheel.sh --plat-name manylinux2014_aarch64
|
||||
elif [ ${{ matrix.config.name }} == 'manylinux2014_x86_64' ]; then
|
||||
docker run --rm -v `pwd`/:/work dockcross/manylinux2014-x64 > ./dockcross
|
||||
chmod +x ./dockcross
|
||||
|
|
|
@ -54,34 +54,34 @@ jobs:
|
|||
archiver: '7z a',
|
||||
generators: 'Ninja'
|
||||
}
|
||||
- {
|
||||
os: windows-2019,
|
||||
arch: x64,
|
||||
python-arch: x64,
|
||||
python-ver: '3.8',
|
||||
name: 'windows-x64 MINGW32 shared',
|
||||
shared: "yes",
|
||||
mingw: MINGW32,
|
||||
mingw-arch: i686,
|
||||
artifact: 'windows_mingw32.7z',
|
||||
build_type: 'Debug',
|
||||
archiver: '7z a',
|
||||
generators: 'Ninja'
|
||||
}
|
||||
- {
|
||||
os: windows-2019,
|
||||
arch: x64,
|
||||
python-arch: x64,
|
||||
python-ver: '3.8',
|
||||
name: 'windows-x64 MINGW32 static',
|
||||
shared: "no",
|
||||
mingw: MINGW32,
|
||||
mingw-arch: i686,
|
||||
artifact: 'windows_mingw32.7z',
|
||||
build_type: 'Debug',
|
||||
archiver: '7z a',
|
||||
generators: 'Ninja'
|
||||
}
|
||||
# - { # This fails randomly which can't be reproduced.
|
||||
# os: windows-2019,
|
||||
# arch: x64,
|
||||
# python-arch: x64,
|
||||
# python-ver: '3.8',
|
||||
# name: 'windows-x64 MINGW32 shared',
|
||||
# shared: "yes",
|
||||
# mingw: MINGW32,
|
||||
# mingw-arch: i686,
|
||||
# artifact: 'windows_mingw32.7z',
|
||||
# build_type: 'Debug',
|
||||
# archiver: '7z a',
|
||||
# generators: 'Ninja'
|
||||
# }
|
||||
# - { # This fails randomly which can't be reproduced.
|
||||
# os: windows-2019,
|
||||
# arch: x64,
|
||||
# python-arch: x64,
|
||||
# python-ver: '3.8',
|
||||
# name: 'windows-x64 MINGW32 static',
|
||||
# shared: "no",
|
||||
# mingw: MINGW32,
|
||||
# mingw-arch: i686,
|
||||
# artifact: 'windows_mingw32.7z',
|
||||
# build_type: 'Debug',
|
||||
# archiver: '7z a',
|
||||
# generators: 'Ninja'
|
||||
# }
|
||||
- {
|
||||
os: windows-2019,
|
||||
arch: x64,
|
||||
|
@ -95,7 +95,7 @@ jobs:
|
|||
archiver: '7z a',
|
||||
generators: 'Visual Studio 16 2019'
|
||||
}
|
||||
- {
|
||||
- {
|
||||
os: windows-2019,
|
||||
arch: x86,
|
||||
python-arch: x86,
|
||||
|
@ -328,9 +328,9 @@ jobs:
|
|||
brew install p7zip cmake ninja
|
||||
mkdir build
|
||||
mkdir instdir
|
||||
cmake . -DCMAKE_TOOLCHAIN_FILE="$ANDROID_HOME/ndk/21.4.7075529/build/cmake/android.toolchain.cmake" \
|
||||
cmake . -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK/build/cmake/android.toolchain.cmake" \
|
||||
-DANDROID_PLATFORM=android-28 \
|
||||
-DANDROID_NDK="$ANDROID_HOME/ndk/21.4.7075529" \
|
||||
-DANDROID_NDK="$ANDROID_NDK" \
|
||||
-DANDROID_ABI=${{ matrix.config.arch }} \
|
||||
-DOLP_SDK_ENABLE_TESTING=NO \
|
||||
-DOLP_SDK_BUILD_EXAMPLES=ON \
|
||||
|
|
|
@ -14,5 +14,5 @@ jobs:
|
|||
days-before-stale: 60
|
||||
days-before-close: 15
|
||||
exempt-all-milestones: true
|
||||
exempt-issue-labels: 'pinned'
|
||||
exempt-issue-labels: 'pinned,help wanted'
|
||||
exempt-pr-labels: 'pinned'
|
||||
|
|
|
@ -3,16 +3,18 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
if(MSVC)
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.15")
|
||||
# set all policies to max supported by actual running cmake version
|
||||
# mainly want the following:
|
||||
# CMP0091: prevent msvcrt flags being added to default CMAKE_<LANG>_FLAGS_<CONFIG>
|
||||
# CMP0092: prevent warning flags being added to default CMAKE_<LANG>_FLAGS
|
||||
cmake_policy(VERSION ${CMAKE_VERSION})
|
||||
else()
|
||||
message(FATAL_ERROR "please update cmake")
|
||||
endif()
|
||||
# Only required for MSVC, but we can't know the compiler at this point because we haven't
|
||||
# called enable_language() or project(), and if we did that it would lock in the old
|
||||
# policy. Setting these policies is harmless for non-MSVC though, so just enable them
|
||||
# always.
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.15")
|
||||
# Set explicitly the policies we want rather than raising the base to the current
|
||||
# version. This prevents unintended behavior changes as CMake evolves and provides a
|
||||
# consistent experience across different CMake versions.
|
||||
# CMP0091: prevent msvcrt flags being added to default CMAKE_<LANG>_FLAGS_<CONFIG>
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
# CMP0092: prevent warning flags being added to default CMAKE_<LANG>_FLAGS for MSVC
|
||||
cmake_policy(SET CMP0092 NEW)
|
||||
endif()
|
||||
|
||||
# Workaround to fix wrong compiler on macos.
|
||||
|
@ -31,6 +33,13 @@ endif()
|
|||
|
||||
project(unicorn C)
|
||||
|
||||
# We depend on the availability of the CMAKE_MSVC_RUNTIME_LIBRARY, which is only
|
||||
# available in CMake 3.15 and above (see also the comments above in regards to policy
|
||||
# CMP0091).
|
||||
if(MSVC AND CMAKE_VERSION VERSION_LESS "3.15")
|
||||
message(FATAL_ERROR "Please update CMake to 3.15 or greater.")
|
||||
endif()
|
||||
|
||||
# mainline qemu mostly just uses compiler default
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
|
@ -1403,6 +1412,9 @@ if(UNICORN_BUILD_TESTS)
|
|||
add_executable(${TEST_FILE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tests/unit/${TEST_FILE}.c
|
||||
)
|
||||
target_compile_options(${TEST_FILE} PRIVATE
|
||||
${UNICORN_COMPILE_OPTIONS}
|
||||
)
|
||||
target_link_libraries(${TEST_FILE} PRIVATE
|
||||
${SAMPLES_LIB}
|
||||
)
|
||||
|
@ -1412,6 +1424,9 @@ if(UNICORN_BUILD_TESTS)
|
|||
file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb shell \"chmod +x /data/local/tmp/build/${TEST_FILE}\"\n")
|
||||
file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb shell \'LD_LIBRARY_PATH=/data/local/tmp/build:$LD_LIBRARY_PATH /data/local/tmp/build/${TEST_FILE}\' || exit -1\n")
|
||||
endif()
|
||||
if (UNICORN_TARGET_ARCH STREQUAL "aarch64" OR UNICORN_TARGET_ARCH STREQUAL "ppc")
|
||||
target_compile_definitions(${TEST_FILE} PRIVATE TARGET_READ_INLINED)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
|
38
ChangeLog
38
ChangeLog
|
@ -1,5 +1,43 @@
|
|||
This file details the changelog of Unicorn Engine.
|
||||
|
||||
-------------------------------
|
||||
[Version 2.0.1]: Nov 1st, 2022
|
||||
|
||||
Unicorn2 makes the first step to [Debian packages](https://tracker.debian.org/pkg/unicorn-engine) and [vcpkg](https://github.com/microsoft/vcpkg/pull/26101)! Thanks @roehling and @LilyWangL !
|
||||
|
||||
Features:
|
||||
|
||||
- Support building & running on BE hosts. #1710
|
||||
- Fix and support `clang-cl` on Windows. #1687
|
||||
- Fix python `sdist` and add aarch64 Linux wheels. Note `pip` can build Unicorn2 on M1 now!
|
||||
- C# binding is refined and upgraded to .Net 6. #1723
|
||||
|
||||
Fix/Improvements:
|
||||
|
||||
- Various bindings improvements. #1723
|
||||
- Improvements for tests. #1684 #1683 #1691 #1711
|
||||
- Fail explicitly when VEX.L is set. #1658
|
||||
- Fix endianness when writing PPC32 CR register. #1659
|
||||
- Fix a bug in `uc_ctl_set_cpu_model` check.
|
||||
- Fix Tricore PC not updating. #1668
|
||||
- Fix the mapping not updated if users modify the mappings in the hooks.
|
||||
- Handle pathological cases consistently. #1651
|
||||
- Fix memory leaks in PPC target. #1680
|
||||
- Fix memory leaks in Tricore target. #1681
|
||||
- Fix MSVC handling in cmake. #1693
|
||||
- Fix PC sync-ing problems for `UC_HOOK_BLOCK` hooks.
|
||||
- Fix PC sync-ed twice when users request a soft restart.
|
||||
- Prevent overflow with pre-allocated RAM blocks. #1712
|
||||
- Add FPCR and FPSR registers #1722
|
||||
- Fix ARM CPU state not deep copied.
|
||||
- Fix PC not sync-ed for memory operation on aarch64.
|
||||
- Exit invalid store operations early to avoid the target registers being overwritten.
|
||||
- Improve the support for ARM BE32.
|
||||
|
||||
Thanks:
|
||||
|
||||
@roehling @LilyWangL @mrexodia @zachriggle @Yu3H0 @rhelmot @relapids @sh4w1 @TSRBerry
|
||||
|
||||
-------------------------------
|
||||
[Version 2.0.0]: July 7th, 2022
|
||||
|
||||
|
|
|
@ -7,15 +7,19 @@ from source.
|
|||
|
||||
1. Compile the code
|
||||
|
||||
[Windows]
|
||||
To compile the code open the UnicornSln.sln with Microsoft Visual
|
||||
Studio 12 or with a newer version and just press Ctrl+Shift+B to build
|
||||
the solution.
|
||||
|
||||
You need to have installed at least version 4.5 of the .NET framework.
|
||||
|
||||
[Linux]
|
||||
TODO
|
||||
You need to have at least version 5.0 of .NET installed.
|
||||
|
||||
1. Windows
|
||||
|
||||
To compile the code open the UnicornSln.sln with Microsoft Visual
|
||||
Studio 12 or with a newer version and just press Ctrl+Shift+B to build
|
||||
the solution.
|
||||
|
||||
2. Linux
|
||||
|
||||
To compile the code open a terminal in this directory
|
||||
and enter the following command to build the solution:
|
||||
`dotnet build`
|
||||
|
||||
2. Usage
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
namespace UnicornManaged.AssemblyInfo
|
||||
|
||||
open System.Reflection
|
||||
open System.Runtime.CompilerServices
|
||||
open System.Runtime.InteropServices
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[<assembly: AssemblyTitle("UnicornManaged")>]
|
||||
[<assembly: AssemblyDescription("")>]
|
||||
[<assembly: AssemblyConfiguration("")>]
|
||||
[<assembly: AssemblyCompany("")>]
|
||||
[<assembly: AssemblyProduct("UnicornManaged")>]
|
||||
[<assembly: AssemblyCopyright("Copyright © Antonio Parata 2016")>]
|
||||
[<assembly: AssemblyTrademark("")>]
|
||||
[<assembly: AssemblyCulture("")>]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[<assembly: ComVisible(false)>]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[<assembly: Guid("0c21f1c1-2725-4a46-9022-1905f85822a5")>]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [<assembly: AssemblyVersion("1.0.*")>]
|
||||
[<assembly: AssemblyVersion("1.0.0.0")>]
|
||||
[<assembly: AssemblyFileVersion("1.0.0.0")>]
|
||||
|
||||
do
|
||||
()
|
|
@ -1,13 +1,11 @@
|
|||
namespace UnicornManaged.Binding
|
||||
|
||||
open System
|
||||
|
||||
module BindingFactory =
|
||||
let mutable _instance = NativeBinding.instance
|
||||
|
||||
let setDefaultBinding(binding: IBinding) =
|
||||
_instance <- binding
|
||||
|
||||
|
||||
let getDefault() =
|
||||
_instance
|
||||
|
||||
|
|
|
@ -318,7 +318,11 @@ module Arm64 =
|
|||
let UC_ARM64_REG_VBAR_EL2 = 288
|
||||
let UC_ARM64_REG_VBAR_EL3 = 289
|
||||
let UC_ARM64_REG_CP_REG = 290
|
||||
let UC_ARM64_REG_ENDING = 291
|
||||
|
||||
// floating point control and status registers
|
||||
let UC_ARM64_REG_FPCR = 291
|
||||
let UC_ARM64_REG_FPSR = 292
|
||||
let UC_ARM64_REG_ENDING = 293
|
||||
|
||||
// alias registers
|
||||
let UC_ARM64_REG_IP0 = 215
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
namespace UnicornManaged
|
||||
|
||||
|
||||
open System
|
||||
open System.Threading
|
||||
open System.Collections.Generic
|
||||
open System.Runtime.InteropServices
|
||||
open System.Linq
|
||||
|
@ -20,7 +19,7 @@ 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) =
|
||||
and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
||||
|
||||
// hook callback list
|
||||
let _codeHooks = new List<(CodeHook * Object)>()
|
||||
|
@ -43,24 +42,24 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
(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
|
||||
do
|
||||
// initialize event list
|
||||
_eventMemMap
|
||||
|> Seq.map(fun kv -> kv.Key)
|
||||
|
@ -72,7 +71,7 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
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
|
||||
|
@ -82,43 +81,43 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
|
||||
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
|
||||
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 -> ()
|
||||
|
||||
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 -> ()
|
||||
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 -> ()
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
match binding.RegRead(_eng.[0], regId, regValue) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.RegRead(regId: Int32) =
|
||||
|
@ -127,15 +126,15 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
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
|
||||
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
|
||||
match binding.EmuStop(_eng.[0]) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
|
||||
member this.Close() =
|
||||
match binding.Close(_eng.[0]) |> this.CheckResult with
|
||||
match binding.Close(_eng.[0]) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.ArchSupported(arch: Int32) =
|
||||
|
@ -148,15 +147,15 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
let errorStringPointer = binding.Strerror(errorNo)
|
||||
Marshal.PtrToStringAnsi(errorStringPointer)
|
||||
|
||||
member this.AddCodeHook(callback: CodeHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
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 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
|
||||
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)
|
||||
|
@ -167,7 +166,7 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
member this.HookDel(callback: CodeHook) =
|
||||
hookDel _codeHooks callback
|
||||
|
||||
member this.AddBlockHook(callback: BlockHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
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))
|
||||
|
@ -175,7 +174,7 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
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
|
||||
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)
|
||||
|
@ -183,15 +182,15 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
member this.HookDel(callback: BlockHook) =
|
||||
hookDel _blockHooks callback
|
||||
|
||||
member this.AddInterruptHook(callback: InterruptHook, userData: Object, hookBegin: UInt64, hookEnd : UInt64) =
|
||||
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
|
||||
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)
|
||||
|
@ -202,7 +201,7 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
member this.HookDel(callback: InterruptHook) =
|
||||
hookDel _interruptHooks callback
|
||||
|
||||
member this.AddMemReadHook(callback: MemReadHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
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))
|
||||
|
@ -210,7 +209,7 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
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
|
||||
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)
|
||||
|
@ -218,15 +217,15 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
member this.HookDel(callback: MemReadHook) =
|
||||
hookDel _memReadHooks callback
|
||||
|
||||
member this.AddMemWriteHook(callback: MemWriteHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
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
|
||||
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)
|
||||
|
@ -235,7 +234,7 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
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) =
|
||||
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])
|
||||
|
@ -249,12 +248,12 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
|> 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
|
||||
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
|
||||
// register the callbacks
|
||||
_memEventHooks.Keys
|
||||
|> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0)
|
||||
|> Seq.iter(fun eventFlag -> _memEventHooks.[eventFlag].Add((callback, userData)))
|
||||
|
@ -271,11 +270,11 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
_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
|
||||
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)
|
||||
|
@ -287,11 +286,11 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
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
|
||||
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)
|
||||
|
@ -303,18 +302,18 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
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
|
||||
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)
|
||||
|
@ -340,4 +339,4 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
|||
|
||||
interface IDisposable with
|
||||
member this.Dispose() =
|
||||
this.Dispose()
|
||||
this.Dispose()
|
||||
|
|
|
@ -1,56 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>0c21f1c1-2725-4a46-9022-1905f85822a5</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>UnicornManaged</RootNamespace>
|
||||
<AssemblyName>UnicornManaged</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFSharpCoreVersion>4.3.1.0</TargetFSharpCoreVersion>
|
||||
<Copyright>Copyright © Antonio Parata 2016</Copyright>
|
||||
<RepositoryUrl>https://github.com/unicorn-engine/unicorn</RepositoryUrl>
|
||||
<Version>2.0.0</Version>
|
||||
<ProjectGuid>0c21f1c1-2725-4a46-9022-1905f85822a5</ProjectGuid>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Name>UnicornManaged</Name>
|
||||
<TargetFrameworkProfile />
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<Tailcalls>false</Tailcalls>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
|
||||
<PropertyGroup>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\UnicornManaged.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<Tailcalls>true</Tailcalls>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<DocumentationFile>bin\Release\UnicornManaged.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyInfo.fs" />
|
||||
<Compile Include="Const\Arm.fs" />
|
||||
<Compile Include="Const\Arm64.fs" />
|
||||
<Compile Include="Const\Common.fs" />
|
||||
<Compile Include="Const\M68k.fs" />
|
||||
<Compile Include="Const\Mips.fs" />
|
||||
<Compile Include="Const\Ppc.fs" />
|
||||
<Compile Include="Const\Riscv.fs" />
|
||||
<Compile Include="Const\S390x.fs" />
|
||||
<Compile Include="Const\Sparc.fs" />
|
||||
<Compile Include="Const\TriCore.fs" />
|
||||
<Compile Include="Const\X86.fs" />
|
||||
<Compile Include="Binding\IBinding.fs" />
|
||||
<Compile Include="Binding\MockBinding.fs" />
|
||||
|
@ -61,27 +36,4 @@
|
|||
<Compile Include="ConvertUtility.fs" />
|
||||
<Compile Include="Unicorn.fs" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<Import Project="$(FSharpTargetsPath)" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
|
||||
</startup>
|
||||
</configuration>
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
namespace UnicornSamples
|
||||
{
|
||||
class Program
|
||||
internal static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
// X86 tests 32bit
|
||||
X86Sample32.X86Code32();
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicornSamples")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicornSamples")]
|
||||
[assembly: AssemblyCopyright("Copyright © Antonio Parata 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b80b5987-1e24-4309-8bf9-c4f91270f21c")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,24 +1,20 @@
|
|||
using Gee.External.Capstone;
|
||||
using Gee.External.Capstone.X86;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnicornManaged;
|
||||
using UnicornManaged.Const;
|
||||
|
||||
namespace UnicornSamples
|
||||
{
|
||||
internal class ShellcodeSample
|
||||
internal static class ShellcodeSample
|
||||
{
|
||||
private const Int64 ADDRESS = 0x1000000;
|
||||
private const long ADDRESS = 0x1000000;
|
||||
|
||||
public static void X86Code32Self()
|
||||
{
|
||||
Byte[] X86_CODE32_SELF =
|
||||
byte[] X86_CODE32_SELF =
|
||||
{
|
||||
0xeb, 0x1c, 0x5a, 0x89, 0xd6, 0x8b, 0x02, 0x66, 0x3d, 0xca, 0x7d, 0x75, 0x06, 0x66, 0x05, 0x03, 0x03,
|
||||
0x89, 0x02, 0xfe, 0xc2, 0x3d, 0x41, 0x41, 0x41, 0x41, 0x75, 0xe9, 0xff, 0xe6, 0xe8, 0xdf, 0xff, 0xff,
|
||||
|
@ -31,7 +27,7 @@ namespace UnicornSamples
|
|||
|
||||
public static void X86Code32()
|
||||
{
|
||||
Byte[] X86_CODE32 =
|
||||
byte[] X86_CODE32 =
|
||||
{
|
||||
0xeb, 0x19, 0x31, 0xc0, 0x31, 0xdb, 0x31, 0xd2, 0x31, 0xc9, 0xb0, 0x04, 0xb3, 0x01, 0x59, 0xb2, 0x05,
|
||||
0xcd, 0x80, 0x31, 0xc0, 0xb0, 0x01, 0x31, 0xdb, 0xcd, 0x80, 0xe8, 0xe2, 0xff, 0xff, 0xff, 0x68, 0x65,
|
||||
|
@ -41,39 +37,39 @@ namespace UnicornSamples
|
|||
Run(X86_CODE32);
|
||||
}
|
||||
|
||||
private static void Run(Byte[] code)
|
||||
private static void Run(byte[] code)
|
||||
{
|
||||
Console.WriteLine();
|
||||
var stackTrace = new StackTrace();
|
||||
var stackFrame = stackTrace.GetFrames()[1];
|
||||
var methodName = stackFrame.GetMethod().Name;
|
||||
|
||||
Console.WriteLine("*** Start: " + methodName);
|
||||
Console.WriteLine($"*** Start: {methodName}");
|
||||
RunTest(code, ADDRESS);
|
||||
Console.WriteLine("*** End: " + methodName);
|
||||
Console.WriteLine($"*** End: {methodName}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
|
||||
private static void RunTest(Byte[] code, Int64 address)
|
||||
private static void RunTest(byte[] code, long address)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var u = new Unicorn(Common.UC_ARCH_X86, Common.UC_MODE_32))
|
||||
using(var disassembler = CapstoneDisassembler.CreateX86Disassembler(DisassembleMode.Bit32))
|
||||
using(var disassembler = CapstoneDisassembler.CreateX86Disassembler(X86DisassembleMode.Bit32))
|
||||
{
|
||||
Console.WriteLine("Unicorn version: {0}", u.Version());
|
||||
|
||||
Console.WriteLine($"Unicorn version: {u.Version()}");
|
||||
|
||||
// map 2MB of memory for this emulation
|
||||
u.MemMap(address, 2 * 1024 * 1024, Common.UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
u.MemWrite(address, code);
|
||||
|
||||
|
||||
// initialize machine registers
|
||||
u.RegWrite(X86.UC_X86_REG_ESP, Utils.Int64ToBytes(address + 0x200000));
|
||||
|
||||
var regv = new Byte[4];
|
||||
var regv = new byte[4];
|
||||
u.RegRead(X86.UC_X86_REG_ESP, regv);
|
||||
|
||||
// tracing all instructions by having @begin > @end
|
||||
|
@ -84,7 +80,7 @@ namespace UnicornSamples
|
|||
|
||||
// handle SYSCALL
|
||||
u.AddSyscallHook(SyscallHookCallback);
|
||||
|
||||
|
||||
Console.WriteLine(">>> Start tracing code");
|
||||
|
||||
// emulate machine code in infinite time
|
||||
|
@ -98,44 +94,44 @@ namespace UnicornSamples
|
|||
Console.Error.WriteLine("Emulation FAILED! " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CodeHookCallback(
|
||||
CapstoneDisassembler<X86Instruction, X86Register, X86InstructionGroup,X86InstructionDetail> disassembler,
|
||||
Unicorn u,
|
||||
Int64 addr,
|
||||
Int32 size,
|
||||
Object userData)
|
||||
{
|
||||
Console.Write("[+] 0x{0}: ", addr.ToString("X"));
|
||||
|
||||
var eipBuffer = new Byte[4];
|
||||
private static void CodeHookCallback(
|
||||
CapstoneX86Disassembler disassembler,
|
||||
Unicorn u,
|
||||
long addr,
|
||||
int size,
|
||||
object userData)
|
||||
{
|
||||
Console.Write($"[+] 0x{addr:X}: ");
|
||||
|
||||
var eipBuffer = new byte[4];
|
||||
u.RegRead(X86.UC_X86_REG_EIP, eipBuffer);
|
||||
|
||||
var effectiveSize = Math.Min(16, size);
|
||||
var tmp = new Byte[effectiveSize];
|
||||
var tmp = new byte[effectiveSize];
|
||||
u.MemRead(addr, tmp);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var t in tmp)
|
||||
{
|
||||
sb.AppendFormat("{0} ", (0xFF & t).ToString("X"));
|
||||
sb.AppendFormat($"{(0xFF & t):X} ");
|
||||
}
|
||||
Console.Write("{0,-20}", sb);
|
||||
Console.Write($"{sb,-20}");
|
||||
Console.WriteLine(Utils.Disassemble(disassembler, tmp));
|
||||
}
|
||||
|
||||
private static void SyscallHookCallback(Unicorn u, Object userData)
|
||||
private static void SyscallHookCallback(Unicorn u, object userData)
|
||||
{
|
||||
var eaxBuffer = new Byte[4];
|
||||
var eaxBuffer = new byte[4];
|
||||
u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer);
|
||||
var eax = Utils.ToInt(eaxBuffer);
|
||||
|
||||
Console.WriteLine("[!] Syscall EAX = 0x{0}", eax.ToString("X"));
|
||||
Console.WriteLine($"[!] Syscall EAX = 0x{eax:X}");
|
||||
|
||||
u.EmuStop();
|
||||
}
|
||||
|
||||
private static void InterruptHookCallback(Unicorn u, Int32 intNumber, Object userData)
|
||||
private static void InterruptHookCallback(Unicorn u, int intNumber, object userData)
|
||||
{
|
||||
// only handle Linux syscall
|
||||
if (intNumber != 0x80)
|
||||
|
@ -143,8 +139,8 @@ namespace UnicornSamples
|
|||
return;
|
||||
}
|
||||
|
||||
var eaxBuffer = new Byte[4];
|
||||
var eipBuffer = new Byte[4];
|
||||
var eaxBuffer = new byte[4];
|
||||
var eipBuffer = new byte[4];
|
||||
|
||||
u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer);
|
||||
u.RegRead(X86.UC_X86_REG_EIP, eipBuffer);
|
||||
|
@ -155,19 +151,19 @@ namespace UnicornSamples
|
|||
switch (eax)
|
||||
{
|
||||
default:
|
||||
Console.WriteLine("[!] Interrupt 0x{0} num {1}, EAX=0x{2}", eip.ToString("X"), intNumber.ToString("X"), eax.ToString("X"));
|
||||
Console.WriteLine($"[!] Interrupt 0x{eip:X} num {intNumber:X}, EAX=0x{eax:X}");
|
||||
break;
|
||||
case 1: // sys_exit
|
||||
Console.WriteLine("[!] Interrupt 0x{0} num {1}, SYS_EXIT", eip.ToString("X"), intNumber.ToString("X"));
|
||||
Console.WriteLine($"[!] Interrupt 0x{eip:X} num {intNumber:X}, SYS_EXIT");
|
||||
u.EmuStop();
|
||||
break;
|
||||
case 4: // sys_write
|
||||
|
||||
// ECX = buffer address
|
||||
var ecxBuffer = new Byte[4];
|
||||
var ecxBuffer = new byte[4];
|
||||
|
||||
// EDX = buffer size
|
||||
var edxBuffer = new Byte[4];
|
||||
var edxBuffer = new byte[4];
|
||||
|
||||
u.RegRead(X86.UC_X86_REG_ECX, ecxBuffer);
|
||||
u.RegRead(X86.UC_X86_REG_EDX, edxBuffer);
|
||||
|
@ -177,16 +173,11 @@ namespace UnicornSamples
|
|||
|
||||
// read the buffer in
|
||||
var size = Math.Min(256, edx);
|
||||
var buffer = new Byte[size];
|
||||
var buffer = new byte[size];
|
||||
u.MemRead(ecx, buffer);
|
||||
var content = Encoding.Default.GetString(buffer);
|
||||
|
||||
Console.WriteLine(
|
||||
"[!] Interrupt 0x{0}: num {1}, SYS_WRITE. buffer = 0x{2}, size = , content = '{3}'",
|
||||
eip.ToString("X"),
|
||||
ecx.ToString("X"),
|
||||
edx.ToString("X"),
|
||||
content);
|
||||
Console.WriteLine($"[!] Interrupt 0x{eip:X}: num {ecx:X}, SYS_WRITE. buffer = 0x{edx:X}, size = {size:X}, content = '{content}'");
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,108 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{B80B5987-1E24-4309-8BF9-C4F91270F21C}</ProjectGuid>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>UnicornSamples</RootNamespace>
|
||||
<AssemblyName>UnicornSamples</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Copyright>Copyright © Antonio Parata 2016</Copyright>
|
||||
<RepositoryUrl>https://github.com/unicorn-engine/unicorn</RepositoryUrl>
|
||||
<Version>2.0.0</Version>
|
||||
<ProjectGuid>{B80B5987-1E24-4309-8BF9-C4F91270F21C}</ProjectGuid>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<CodeAnalysisIgnoreGeneratedCode>false</CodeAnalysisIgnoreGeneratedCode>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
|
||||
<PropertyGroup>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Gee.External.Capstone, Version=1.2.2.0, Culture=neutral, processorArchitecture=x86">
|
||||
<HintPath>..\packages\Gee.External.Capstone.1.2.2\lib\net45\Gee.External.Capstone.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ShellcodeSample.cs" />
|
||||
<Compile Include="Utils.cs" />
|
||||
<Compile Include="X86Sample32.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UnicornManaged\UnicornManaged.fsproj">
|
||||
<Project>{0c21f1c1-2725-4a46-9022-1905f85822a5}</Project>
|
||||
<Name>UnicornManaged</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="capstone.dll" />
|
||||
<Content Include="Gee.External.Capstone.Proxy.dll" />
|
||||
<PackageReference Include="Gee.External.Capstone" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -1,45 +1,41 @@
|
|||
using Gee.External.Capstone;
|
||||
using Gee.External.Capstone.X86;
|
||||
using Gee.External.Capstone.X86;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UnicornSamples
|
||||
{
|
||||
internal static class Utils
|
||||
{
|
||||
public static Int64 ToInt(Byte[] val)
|
||||
public static long ToInt(byte[] val)
|
||||
{
|
||||
UInt64 res = 0;
|
||||
ulong res = 0;
|
||||
for (var i = 0; i < val.Length; i++)
|
||||
{
|
||||
var v = val[i] & 0xFF;
|
||||
res += (UInt64)(v << (i * 8));
|
||||
res += (ulong)(v << (i * 8));
|
||||
}
|
||||
return (Int64)res;
|
||||
return (long)res;
|
||||
}
|
||||
|
||||
public static Byte[] Int64ToBytes(Int64 intVal)
|
||||
public static byte[] Int64ToBytes(long intVal)
|
||||
{
|
||||
var res = new Byte[8];
|
||||
var uval = (UInt64)intVal;
|
||||
var res = new byte[8];
|
||||
var uval = (ulong)intVal;
|
||||
for (var i = 0; i < res.Length; i++)
|
||||
{
|
||||
res[i] = (Byte)(uval & 0xff);
|
||||
res[i] = (byte)(uval & 0xff);
|
||||
uval = uval >> 8;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static String Disassemble(CapstoneDisassembler<X86Instruction, X86Register, X86InstructionGroup, X86InstructionDetail> disassembler, Byte[] code)
|
||||
public static string Disassemble(CapstoneX86Disassembler disassembler, byte[] code)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var instructions = disassembler.DisassembleAll(code);
|
||||
var instructions = disassembler.Disassemble(code);
|
||||
foreach (var instruction in instructions)
|
||||
{
|
||||
sb.AppendFormat("{0} {1}{2}", instruction.Mnemonic, instruction.Operand, Environment.NewLine);
|
||||
sb.AppendFormat($"{instruction.Mnemonic} {instruction.Operand}{Environment.NewLine}");
|
||||
}
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
|
|
|
@ -1,34 +1,30 @@
|
|||
using Gee.External.Capstone;
|
||||
using Gee.External.Capstone.X86;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnicornManaged;
|
||||
using UnicornManaged.Const;
|
||||
|
||||
namespace UnicornSamples
|
||||
{
|
||||
internal class X86Sample32
|
||||
internal static class X86Sample32
|
||||
{
|
||||
private const Int64 ADDRESS = 0x1000000;
|
||||
private const long ADDRESS = 0x1000000;
|
||||
|
||||
public static void X86Code32()
|
||||
{
|
||||
Byte[] X86_CODE32 =
|
||||
byte[] X86_CODE32 =
|
||||
{
|
||||
// INC ecx; DEC edx
|
||||
0x41, 0x4a
|
||||
};
|
||||
Run(X86_CODE32);
|
||||
}
|
||||
|
||||
|
||||
public static void X86Code32InvalidMemRead()
|
||||
{
|
||||
Byte[] X86_CODE32_MEM_READ =
|
||||
byte[] X86_CODE32_MEM_READ =
|
||||
{
|
||||
// mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
||||
0x8B, 0x0D, 0xAA, 0xAA, 0xAA, 0xAA, 0x41, 0x4a
|
||||
|
@ -38,7 +34,7 @@ namespace UnicornSamples
|
|||
|
||||
public static void X86Code32InvalidMemWriteWithRuntimeFix()
|
||||
{
|
||||
Byte[] X86_CODE32_MEM_WRITE =
|
||||
byte[] X86_CODE32_MEM_WRITE =
|
||||
{
|
||||
// mov [0xaaaaaaaa], ecx; INC ecx; DEC edx
|
||||
0x89, 0x0D, 0xAA, 0xAA, 0xAA, 0xAA, 0x41, 0x4a
|
||||
|
@ -48,7 +44,7 @@ namespace UnicornSamples
|
|||
|
||||
public static void X86Code32InOut()
|
||||
{
|
||||
Byte[] X86_CODE32_INOUT =
|
||||
byte[] X86_CODE32_INOUT =
|
||||
{
|
||||
// INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
|
||||
0x41, 0xE4, 0x3F, 0x4a, 0xE6, 0x46, 0x43
|
||||
|
@ -57,14 +53,14 @@ namespace UnicornSamples
|
|||
}
|
||||
|
||||
|
||||
private static void Run(Byte[] code, Boolean raiseException = false)
|
||||
private static void Run(byte[] code, bool raiseException = false)
|
||||
{
|
||||
Console.WriteLine();
|
||||
var stackTrace = new StackTrace();
|
||||
var stackFrame = stackTrace.GetFrames()[1];
|
||||
var methodName = stackFrame.GetMethod().Name;
|
||||
var methodName = stackFrame.GetMethod()?.Name;
|
||||
|
||||
Console.WriteLine("*** Start: " + methodName);
|
||||
Console.WriteLine($"*** Start: {methodName}");
|
||||
Exception e = null;
|
||||
try
|
||||
{
|
||||
|
@ -84,93 +80,88 @@ namespace UnicornSamples
|
|||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private static void RunTest(Byte[] code, Int64 address, Int32 mode)
|
||||
private static void RunTest(byte[] code, long address, int mode)
|
||||
{
|
||||
using (var u = new Unicorn(Common.UC_ARCH_X86, mode))
|
||||
using (var disassembler = CapstoneDisassembler.CreateX86Disassembler(DisassembleMode.Bit32))
|
||||
{
|
||||
Console.WriteLine("Unicorn version: {0}", u.Version());
|
||||
using var u = new Unicorn(Common.UC_ARCH_X86, mode);
|
||||
using var disassembler = CapstoneDisassembler.CreateX86Disassembler(X86DisassembleMode.Bit32);
|
||||
Console.WriteLine($"Unicorn version: {u.Version()}");
|
||||
|
||||
// map 2MB of memory for this emulation
|
||||
u.MemMap(address, 2 * 1024 * 1024, Common.UC_PROT_ALL);
|
||||
// map 2MB of memory for this emulation
|
||||
u.MemMap(address, 2 * 1024 * 1024, Common.UC_PROT_ALL);
|
||||
|
||||
// initialize machine registers
|
||||
u.RegWrite(X86.UC_X86_REG_EAX, 0x1234);
|
||||
u.RegWrite(X86.UC_X86_REG_ECX, 0x1234);
|
||||
u.RegWrite(X86.UC_X86_REG_EDX, 0x7890);
|
||||
// initialize machine registers
|
||||
u.RegWrite(X86.UC_X86_REG_EAX, 0x1234);
|
||||
u.RegWrite(X86.UC_X86_REG_ECX, 0x1234);
|
||||
u.RegWrite(X86.UC_X86_REG_EDX, 0x7890);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
u.MemWrite(address, code);
|
||||
// write machine code to be emulated to memory
|
||||
u.MemWrite(address, code);
|
||||
|
||||
// initialize machine registers
|
||||
u.RegWrite(X86.UC_X86_REG_ESP, Utils.Int64ToBytes(address + 0x200000));
|
||||
// initialize machine registers
|
||||
u.RegWrite(X86.UC_X86_REG_ESP, Utils.Int64ToBytes(address + 0x200000));
|
||||
|
||||
// handle IN & OUT instruction
|
||||
u.AddInHook(InHookCallback);
|
||||
u.AddOutHook(OutHookCallback);
|
||||
// handle IN & OUT instruction
|
||||
u.AddInHook(InHookCallback);
|
||||
u.AddOutHook(OutHookCallback);
|
||||
|
||||
// tracing all instructions by having @begin > @end
|
||||
u.AddCodeHook((uc, addr, size, userData) => CodeHookCallback(disassembler, uc, addr, size, userData), 1, 0);
|
||||
// tracing all instructions by having @begin > @end
|
||||
u.AddCodeHook((uc, addr, size, userData) => CodeHookCallback(disassembler, uc, addr, size, userData), 1, 0);
|
||||
|
||||
// handle interrupt ourself
|
||||
u.AddInterruptHook(InterruptHookCallback);
|
||||
// handle interrupt ourself
|
||||
u.AddInterruptHook(InterruptHookCallback);
|
||||
|
||||
// handle SYSCALL
|
||||
u.AddSyscallHook(SyscallHookCallback);
|
||||
// handle SYSCALL
|
||||
u.AddSyscallHook(SyscallHookCallback);
|
||||
|
||||
// intercept invalid memory events
|
||||
u.AddEventMemHook(MemMapHookCallback, Common.UC_HOOK_MEM_READ_UNMAPPED | Common.UC_HOOK_MEM_WRITE_UNMAPPED);
|
||||
// intercept invalid memory events
|
||||
u.AddEventMemHook(MemMapHookCallback, Common.UC_HOOK_MEM_READ_UNMAPPED | Common.UC_HOOK_MEM_WRITE_UNMAPPED);
|
||||
|
||||
Console.WriteLine(">>> Start tracing code");
|
||||
Console.WriteLine(">>> Start tracing code");
|
||||
|
||||
// emulate machine code in infinite time
|
||||
u.EmuStart(address, address + code.Length, 0u, 0u);
|
||||
// emulate machine code in infinite time
|
||||
u.EmuStart(address, address + code.Length, 0u, 0u);
|
||||
|
||||
// print registers
|
||||
var ecx = u.RegRead(X86.UC_X86_REG_ECX);
|
||||
var edx = u.RegRead(X86.UC_X86_REG_EDX);
|
||||
var eax = u.RegRead(X86.UC_X86_REG_EAX);
|
||||
Console.WriteLine("[!] EAX = {0}", eax.ToString("X"));
|
||||
Console.WriteLine("[!] ECX = {0}", ecx.ToString("X"));
|
||||
Console.WriteLine("[!] EDX = {0}", edx.ToString("X"));
|
||||
// print registers
|
||||
var ecx = u.RegRead(X86.UC_X86_REG_ECX);
|
||||
var edx = u.RegRead(X86.UC_X86_REG_EDX);
|
||||
var eax = u.RegRead(X86.UC_X86_REG_EAX);
|
||||
Console.WriteLine($"[!] EAX = {eax:X}");
|
||||
Console.WriteLine($"[!] ECX = {ecx:X}");
|
||||
Console.WriteLine($"[!] EDX = {edx:X}");
|
||||
|
||||
Console.WriteLine(">>> Emulation Done!");
|
||||
}
|
||||
Console.WriteLine(">>> Emulation Done!");
|
||||
}
|
||||
|
||||
private static Int32 InHookCallback(Unicorn u, Int32 port, Int32 size, Object userData)
|
||||
private static int InHookCallback(Unicorn u, int port, int size, object userData)
|
||||
{
|
||||
var eip = u.RegRead(X86.UC_X86_REG_EIP);
|
||||
Console.WriteLine("[!] Reading from port 0x{0}, size: {1}, address: 0x{2}", port.ToString("X"), size.ToString("X"), eip.ToString("X"));
|
||||
var res = 0;
|
||||
switch (size)
|
||||
var eip = u.RegRead(X86.UC_X86_REG_EIP);
|
||||
Console.WriteLine($"[!] Reading from port 0x{port:X}, size: {size:X}, address: 0x{eip:X}");
|
||||
var res = size switch
|
||||
{
|
||||
case 1:
|
||||
1 =>
|
||||
// read 1 byte to AL
|
||||
res = 0xf1;
|
||||
break;
|
||||
case 2:
|
||||
0xf1,
|
||||
2 =>
|
||||
// read 2 byte to AX
|
||||
res = 0xf2;
|
||||
break;
|
||||
case 4:
|
||||
0xf2,
|
||||
4 =>
|
||||
// read 4 byte to EAX
|
||||
res = 0xf4;
|
||||
break;
|
||||
}
|
||||
0xf4,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
Console.WriteLine("[!] Return value: {0}", res.ToString("X"));
|
||||
Console.WriteLine($"[!] Return value: {res:X}");
|
||||
return res;
|
||||
}
|
||||
|
||||
private static void OutHookCallback(Unicorn u, Int32 port, Int32 size, Int32 value, Object userData)
|
||||
private static void OutHookCallback(Unicorn u, int port, int size, int value, object userData)
|
||||
{
|
||||
var eip = u.RegRead(X86.UC_X86_REG_EIP);
|
||||
Console.WriteLine("[!] Writing to port 0x{0}, size: {1}, value: 0x{2}, address: 0x{3}", port.ToString("X"), size.ToString("X"), value.ToString("X"), eip.ToString("X"));
|
||||
Console.WriteLine($"[!] Writing to port 0x{port:X}, size: {size:X}, value: 0x{value:X}, address: 0x{eip:X}");
|
||||
|
||||
// confirm that value is indeed the value of AL/ AX / EAX
|
||||
var v = 0L;
|
||||
var regName = String.Empty;
|
||||
var regName = string.Empty;
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
|
@ -190,85 +181,81 @@ namespace UnicornSamples
|
|||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine("[!] Register {0}: {1}", regName, v.ToString("X"));
|
||||
Console.WriteLine("[!] Register {0}: {1:X}", regName, v);
|
||||
}
|
||||
|
||||
private static Boolean MemMapHookCallback(Unicorn u, Int32 eventType, Int64 address, Int32 size, Int64 value, Object userData)
|
||||
private static bool MemMapHookCallback(Unicorn u, int eventType, long address, int size, long value, object userData)
|
||||
{
|
||||
if (eventType == Common.UC_MEM_WRITE_UNMAPPED)
|
||||
{
|
||||
Console.WriteLine("[!] Missing memory is being WRITE at 0x{0}, data size = {1}, data value = 0x{2}. Map memory.", address.ToString("X"), size.ToString("X"), value.ToString("X"));
|
||||
u.MemMap(0xaaaa0000, 2 * 1024 * 1024, Common.UC_PROT_ALL);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (eventType != Common.UC_MEM_WRITE_UNMAPPED) return false;
|
||||
|
||||
Console.WriteLine($"[!] Missing memory is being WRITE at 0x{address:X}, data size = {size:X}, data value = 0x{value:X}. Map memory.");
|
||||
u.MemMap(0xaaaa0000, 2 * 1024 * 1024, Common.UC_PROT_ALL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void CodeHookCallback1(
|
||||
CapstoneDisassembler<X86Instruction, X86Register, X86InstructionGroup, X86InstructionDetail> disassembler,
|
||||
CapstoneX86Disassembler disassembler,
|
||||
Unicorn u,
|
||||
Int64 addr,
|
||||
Int32 size,
|
||||
Object userData)
|
||||
long addr,
|
||||
int size,
|
||||
object userData)
|
||||
{
|
||||
Console.Write("[+] 0x{0}: ", addr.ToString("X"));
|
||||
Console.Write($"[+] 0x{addr:X}: ");
|
||||
|
||||
var eipBuffer = new Byte[4];
|
||||
var eipBuffer = new byte[4];
|
||||
u.RegRead(X86.UC_X86_REG_EIP, eipBuffer);
|
||||
|
||||
var effectiveSize = Math.Min(16, size);
|
||||
var tmp = new Byte[effectiveSize];
|
||||
var tmp = new byte[effectiveSize];
|
||||
u.MemRead(addr, tmp);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var t in tmp)
|
||||
{
|
||||
sb.AppendFormat("{0} ", (0xFF & t).ToString("X"));
|
||||
sb.AppendFormat($"{(0xFF & t):X} ");
|
||||
}
|
||||
Console.Write("{0,-20}", sb);
|
||||
Console.Write($"{sb,-20}");
|
||||
Console.WriteLine(Utils.Disassemble(disassembler, tmp));
|
||||
}
|
||||
|
||||
private static void CodeHookCallback(
|
||||
CapstoneDisassembler<X86Instruction, X86Register, X86InstructionGroup, X86InstructionDetail> disassembler,
|
||||
CapstoneX86Disassembler disassembler,
|
||||
Unicorn u,
|
||||
Int64 addr,
|
||||
Int32 size,
|
||||
Object userData)
|
||||
long addr,
|
||||
int size,
|
||||
object userData)
|
||||
{
|
||||
Console.Write("[+] 0x{0}: ", addr.ToString("X"));
|
||||
Console.Write($"[+] 0x{addr:X}: ");
|
||||
|
||||
var eipBuffer = new Byte[4];
|
||||
var eipBuffer = new byte[4];
|
||||
u.RegRead(X86.UC_X86_REG_EIP, eipBuffer);
|
||||
|
||||
var effectiveSize = Math.Min(16, size);
|
||||
var tmp = new Byte[effectiveSize];
|
||||
var tmp = new byte[effectiveSize];
|
||||
u.MemRead(addr, tmp);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var t in tmp)
|
||||
{
|
||||
sb.AppendFormat("{0} ", (0xFF & t).ToString("X"));
|
||||
sb.AppendFormat($"{(0xFF & t):X} ");
|
||||
}
|
||||
Console.Write("{0,-20}", sb);
|
||||
Console.Write($"{sb,-20}");
|
||||
Console.WriteLine(Utils.Disassemble(disassembler, tmp));
|
||||
}
|
||||
|
||||
private static void SyscallHookCallback(Unicorn u, Object userData)
|
||||
private static void SyscallHookCallback(Unicorn u, object userData)
|
||||
{
|
||||
var eaxBuffer = new Byte[4];
|
||||
var eaxBuffer = new byte[4];
|
||||
u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer);
|
||||
var eax = Utils.ToInt(eaxBuffer);
|
||||
|
||||
Console.WriteLine("[!] Syscall EAX = 0x{0}", eax.ToString("X"));
|
||||
Console.WriteLine($"[!] Syscall EAX = 0x{eax:X}");
|
||||
|
||||
u.EmuStop();
|
||||
}
|
||||
|
||||
private static void InterruptHookCallback(Unicorn u, Int32 intNumber, Object userData)
|
||||
private static void InterruptHookCallback(Unicorn u, int intNumber, object userData)
|
||||
{
|
||||
// only handle Linux syscall
|
||||
if (intNumber != 0x80)
|
||||
|
@ -276,8 +263,8 @@ namespace UnicornSamples
|
|||
return;
|
||||
}
|
||||
|
||||
var eaxBuffer = new Byte[4];
|
||||
var eipBuffer = new Byte[4];
|
||||
var eaxBuffer = new byte[4];
|
||||
var eipBuffer = new byte[4];
|
||||
|
||||
u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer);
|
||||
u.RegRead(X86.UC_X86_REG_EIP, eipBuffer);
|
||||
|
@ -288,19 +275,19 @@ namespace UnicornSamples
|
|||
switch (eax)
|
||||
{
|
||||
default:
|
||||
Console.WriteLine("[!] Interrupt 0x{0} num {1}, EAX=0x{2}", eip.ToString("X"), intNumber.ToString("X"), eax.ToString("X"));
|
||||
Console.WriteLine($"[!] Interrupt 0x{eip:X} num {intNumber:X}, EAX=0x{eax:X}");
|
||||
break;
|
||||
case 1: // sys_exit
|
||||
Console.WriteLine("[!] Interrupt 0x{0} num {1}, SYS_EXIT", eip.ToString("X"), intNumber.ToString("X"));
|
||||
Console.WriteLine($"[!] Interrupt 0x{eip:X} num {intNumber:X}, SYS_EXIT");
|
||||
u.EmuStop();
|
||||
break;
|
||||
case 4: // sys_write
|
||||
|
||||
// ECX = buffer address
|
||||
var ecxBuffer = new Byte[4];
|
||||
var ecxBuffer = new byte[4];
|
||||
|
||||
// EDX = buffer size
|
||||
var edxBuffer = new Byte[4];
|
||||
var edxBuffer = new byte[4];
|
||||
|
||||
u.RegRead(X86.UC_X86_REG_ECX, ecxBuffer);
|
||||
u.RegRead(X86.UC_X86_REG_EDX, edxBuffer);
|
||||
|
@ -310,16 +297,11 @@ namespace UnicornSamples
|
|||
|
||||
// read the buffer in
|
||||
var size = Math.Min(256, edx);
|
||||
var buffer = new Byte[size];
|
||||
var buffer = new byte[size];
|
||||
u.MemRead(ecx, buffer);
|
||||
var content = Encoding.Default.GetString(buffer);
|
||||
|
||||
Console.WriteLine(
|
||||
"[!] Interrupt 0x{0}: num {1}, SYS_WRITE. buffer = 0x{2}, size = , content = '{3}'",
|
||||
eip.ToString("X"),
|
||||
ecx.ToString("X"),
|
||||
edx.ToString("X"),
|
||||
content);
|
||||
Console.WriteLine($"[!] Interrupt 0x{eip:X}: num {ecx:X}, SYS_WRITE. buffer = 0x{edx:X}, size = {size:X}, content = '{content}'");
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Gee.External.Capstone" version="1.2.2" targetFramework="net45" />
|
||||
</packages>
|
|
@ -313,7 +313,11 @@ const (
|
|||
ARM64_REG_VBAR_EL2 = 288
|
||||
ARM64_REG_VBAR_EL3 = 289
|
||||
ARM64_REG_CP_REG = 290
|
||||
ARM64_REG_ENDING = 291
|
||||
|
||||
// floating point control and status registers
|
||||
ARM64_REG_FPCR = 291
|
||||
ARM64_REG_FPSR = 292
|
||||
ARM64_REG_ENDING = 293
|
||||
|
||||
// alias registers
|
||||
ARM64_REG_IP0 = 215
|
||||
|
|
|
@ -315,7 +315,11 @@ public interface Arm64Const {
|
|||
public static final int UC_ARM64_REG_VBAR_EL2 = 288;
|
||||
public static final int UC_ARM64_REG_VBAR_EL3 = 289;
|
||||
public static final int UC_ARM64_REG_CP_REG = 290;
|
||||
public static final int UC_ARM64_REG_ENDING = 291;
|
||||
|
||||
// floating point control and status registers
|
||||
public static final int UC_ARM64_REG_FPCR = 291;
|
||||
public static final int UC_ARM64_REG_FPSR = 292;
|
||||
public static final int UC_ARM64_REG_ENDING = 293;
|
||||
|
||||
// alias registers
|
||||
public static final int UC_ARM64_REG_IP0 = 215;
|
||||
|
|
|
@ -316,7 +316,11 @@ const
|
|||
UC_ARM64_REG_VBAR_EL2 = 288;
|
||||
UC_ARM64_REG_VBAR_EL3 = 289;
|
||||
UC_ARM64_REG_CP_REG = 290;
|
||||
UC_ARM64_REG_ENDING = 291;
|
||||
|
||||
// floating point control and status registers
|
||||
UC_ARM64_REG_FPCR = 291;
|
||||
UC_ARM64_REG_FPSR = 292;
|
||||
UC_ARM64_REG_ENDING = 293;
|
||||
|
||||
// alias registers
|
||||
UC_ARM64_REG_IP0 = 215;
|
||||
|
|
|
@ -5,10 +5,15 @@ cd bindings/python
|
|||
|
||||
# Compile wheels
|
||||
if [ -f /opt/python/cp36-cp36m/bin/python ];then
|
||||
/opt/python/cp36-cp36m/bin/python setup.py bdist_wheel
|
||||
/opt/python/cp36-cp36m/bin/python setup.py bdist_wheel $@
|
||||
else
|
||||
python3 setup.py bdist_wheel
|
||||
python3 setup.py bdist_wheel $@
|
||||
fi
|
||||
cd dist
|
||||
auditwheel repair *.whl
|
||||
mv -f wheelhouse/*.whl .
|
||||
|
||||
# We can't repair an aarch64 wheel on x64 hosts
|
||||
# https://github.com/pypa/auditwheel/issues/244
|
||||
if [[ ! "$*" =~ "aarch64" ]];then
|
||||
auditwheel repair *.whl
|
||||
mv -f wheelhouse/*.whl .
|
||||
fi
|
|
@ -1,4 +1,5 @@
|
|||
# Unicorn Emulator Engine
|
||||
#!/usr/bin/env python
|
||||
# Sample code for Unicorn.
|
||||
# By Lazymio(@wtdcode), 2021
|
||||
|
||||
from unicorn import *
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# Sample code for S390x of Unicorn.
|
||||
|
||||
from unicorn import *
|
||||
from unicorn.s390x_const import *
|
||||
|
|
|
@ -26,7 +26,7 @@ ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
|
|||
LIBS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'lib')
|
||||
HEADERS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'include')
|
||||
SRC_DIR = os.path.join(ROOT_DIR, 'src')
|
||||
UC_DIR = os.path.join(ROOT_DIR, '../..')
|
||||
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.0"
|
||||
|
@ -60,6 +60,9 @@ def copy_sources():
|
|||
shutil.copytree(os.path.join(ROOT_DIR, '../../include'), os.path.join(SRC_DIR, 'include/'))
|
||||
# make -> configure -> clean -> clean tests fails unless tests is present
|
||||
shutil.copytree(os.path.join(ROOT_DIR, '../../tests'), os.path.join(SRC_DIR, 'tests/'))
|
||||
shutil.copytree(os.path.join(ROOT_DIR, '../../samples'), os.path.join(SRC_DIR, 'samples/'))
|
||||
shutil.copytree(os.path.join(ROOT_DIR, '../../glib_compat'), os.path.join(SRC_DIR, 'glib_compat/'))
|
||||
|
||||
try:
|
||||
# remove site-specific configuration file
|
||||
# might not exist
|
||||
|
@ -69,6 +72,7 @@ def copy_sources():
|
|||
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.[ch]")))
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.mk")))
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.cmake")))
|
||||
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../LICENSE*")))
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../README.md")))
|
||||
|
|
|
@ -311,7 +311,11 @@ UC_ARM64_REG_VBAR_EL1 = 287
|
|||
UC_ARM64_REG_VBAR_EL2 = 288
|
||||
UC_ARM64_REG_VBAR_EL3 = 289
|
||||
UC_ARM64_REG_CP_REG = 290
|
||||
UC_ARM64_REG_ENDING = 291
|
||||
|
||||
# floating point control and status registers
|
||||
UC_ARM64_REG_FPCR = 291
|
||||
UC_ARM64_REG_FPSR = 292
|
||||
UC_ARM64_REG_ENDING = 293
|
||||
|
||||
# alias registers
|
||||
UC_ARM64_REG_IP0 = 215
|
||||
|
|
|
@ -357,15 +357,14 @@ def reg_write(reg_write_func, arch, reg_id, value):
|
|||
reg = uc_arm64_neon128()
|
||||
reg.low_qword = value & 0xffffffffffffffff
|
||||
reg.high_qword = value >> 64
|
||||
|
||||
if arch == uc.UC_ARCH_ARM:
|
||||
if reg_id == arm64_const.UC_ARM64_REG_CP_REG:
|
||||
elif reg_id == arm64_const.UC_ARM64_REG_CP_REG:
|
||||
reg = uc_arm64_cp_reg()
|
||||
if not isinstance(value, tuple) or len(value) != 6:
|
||||
raise UcError(uc.UC_ERR_ARG)
|
||||
reg.crn, reg.crm, reg.op0, reg.op1, reg.op2, reg.val = value
|
||||
|
||||
elif reg_id == arm_const.UC_ARM_REG_CP_REG:
|
||||
if arch == uc.UC_ARCH_ARM:
|
||||
if reg_id == arm_const.UC_ARM_REG_CP_REG:
|
||||
reg = uc_arm_cp_reg()
|
||||
if not isinstance(value, tuple) or len(value) != 8:
|
||||
raise UcError(uc.UC_ERR_ARG)
|
||||
|
@ -561,7 +560,7 @@ class Uc(object):
|
|||
return reg_read(functools.partial(_uc.uc_reg_read, self._uch), self._arch, reg_id, opt)
|
||||
|
||||
# write to a register, tuple for arm cp regs.
|
||||
def reg_write(self, reg_id: Union[int, ARMCPRegValue, ARM64CPRegValue, X86MMRReg, X86FPReg], value: int):
|
||||
def reg_write(self, reg_id: int, value: Union[int, ARMCPRegValue, ARM64CPRegValue, X86MMRReg, X86FPReg]):
|
||||
return reg_write(functools.partial(_uc.uc_reg_write, self._uch), self._arch, reg_id, value)
|
||||
|
||||
# read from MSR - X86 only
|
||||
|
|
|
@ -313,7 +313,11 @@ module UnicornEngine
|
|||
UC_ARM64_REG_VBAR_EL2 = 288
|
||||
UC_ARM64_REG_VBAR_EL3 = 289
|
||||
UC_ARM64_REG_CP_REG = 290
|
||||
UC_ARM64_REG_ENDING = 291
|
||||
|
||||
# floating point control and status registers
|
||||
UC_ARM64_REG_FPCR = 291
|
||||
UC_ARM64_REG_FPSR = 292
|
||||
UC_ARM64_REG_ENDING = 293
|
||||
|
||||
# alias registers
|
||||
UC_ARM64_REG_IP0 = 215
|
||||
|
|
|
@ -128,3 +128,17 @@ mkdir build; cd build
|
|||
cmake .. -DCMAKE_C_COMPILER=gcc-arm-linux-gnueabihf
|
||||
make
|
||||
```
|
||||
|
||||
## Building from vcpkg
|
||||
|
||||
The Unicorn port in vcpkg is kept up to date by Microsoft team members and community contributors. The url of vcpkg is: https://github.com/Microsoft/vcpkg . You can download and install unicorn using the vcpkg dependency manager:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh # ./bootstrap-vcpkg.bat for Windows
|
||||
./vcpkg integrate install
|
||||
./vcpkg install unicorn
|
||||
```
|
||||
|
||||
If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
|
38
docs/FAQ.md
38
docs/FAQ.md
|
@ -9,7 +9,30 @@ Optimize your program with less instrumentation, e.g. by using `UC_HOOK_BLOCK` i
|
|||
|
||||
## Why do I get a wrong PC after emulation stops?
|
||||
|
||||
PC is only guaranteed to be correct if you install `UC_HOOK_CODE`. This is due to the fact that updating PC is a big performance overhead during emulation.
|
||||
Updating PC is a very large overhead (10x slower in the worst case, see FAQ above) for emulation so the PC sync guarantee is explained below:
|
||||
|
||||
- A `UC_HOOK_CODE` is installed. In this case, the PC is sync-ed _everywhere_ within the effective range of the hook. However, on some architectures, the PC might by sync-ed all the time if the hook is installed.
|
||||
- A `UC_HOOK_MEM_READ` or `UC_HOOK_MEM_WRITE` is installed. In this case, the PC is sync-ed exactly before any read/write events within the effective range of the hook.
|
||||
- Emulation (`uc_emu_start`) terminates without any exception. In this case, the PC will point to the next instruction.
|
||||
- No hook mentioned above is installed and emulation terminates with exceptions. In this case, the PC is sync-ed at the basic block boundary, in other words, the first instruction of the basic block where the exception happens.
|
||||
|
||||
Below is an example:
|
||||
|
||||
```
|
||||
mov x0, #1 <--- the PC will be here
|
||||
mov x1, #2
|
||||
ldr x0, [x1] <--- exception here
|
||||
```
|
||||
|
||||
If `ldr x0, [x1]` fails with memory exceptions, the PC will be left at the beginning of the basic block, in this case `mov x0, #1`.
|
||||
|
||||
However, if a `UC_HOOK_MEM_READ` hook is installed, the PC will be sync-ed:
|
||||
|
||||
```
|
||||
mov x0, #1
|
||||
mov x1, #2
|
||||
ldr x0, [x1] <--- exception here and PC sync-ed here
|
||||
```
|
||||
|
||||
## I get an “Unhandled CPU Exception”, why?
|
||||
|
||||
|
@ -30,6 +53,13 @@ On x86, all available instructions are: `in` `out` `syscall` `sysenter` `cpuid`.
|
|||
|
||||
If you are still using Unicorn1, please upgrade to Unicorn2 for better support.
|
||||
|
||||
## Memory hooks get called multiple times for a single instruction
|
||||
|
||||
There are several possibilities, e.g.:
|
||||
|
||||
- The instruction might access memory multiple times like `rep stos` in x86.
|
||||
- The address to access is bad-aligned and thus the MMU emulation will split the access into several aligned memory access. In worst cases on some arch, it leads to byte by byte access.
|
||||
|
||||
## I can't recover from unmapped read/write even I return `true` in the hook, why?
|
||||
|
||||
This is a minor change in memory hooks behavior between Unicorn1 and Unicorn2. To gracefully recover from memory read/write error, you have to map the invalid memory before you return true.
|
||||
|
@ -38,9 +68,11 @@ It is due to the fact that, if users return `true` without memory mapping set up
|
|||
|
||||
See the [sample](https://github.com/unicorn-engine/unicorn/blob/c05fbb7e63aed0b60fc2888e08beceb17bce8ac4/samples/sample_x86.c#L1379-L1393) for details.
|
||||
|
||||
## My MIPS emulation gets weird read/write error and CPU exceptions.
|
||||
## My emulation gets weird read/write error and CPU exceptions.
|
||||
|
||||
Note you might have an address that falls in MIPS `kseg` segments. In that case, MMU is bypassed and you have to make sure the corresponding physical memory is mapped. See [#217](https://github.com/unicorn-engine/unicorn/issues/217), [#1371](https://github.com/unicorn-engine/unicorn/issues/1371), [#1550](https://github.com/unicorn-engine/unicorn/issues/1371).
|
||||
For MIPS, you might have an address that falls in MIPS `kseg` segments. In that case, MMU is bypassed and you have to make sure the corresponding physical memory is mapped. See [#217](https://github.com/unicorn-engine/unicorn/issues/217), [#1371](https://github.com/unicorn-engine/unicorn/issues/1371), [#1550](https://github.com/unicorn-engine/unicorn/issues/1371).
|
||||
|
||||
For ARM, you might have an address that falls in some non-executable segments. For example, for m-class ARM cpu, some memory area is not executable according to [the ARM document](https://developer.arm.com/documentation/ddi0403/d/System-Level-Architecture/System-Address-Map/The-system-address-map?lang=en).
|
||||
|
||||
## KeyboardInterrupt is not raised during `uc.emu_start`
|
||||
|
||||
|
|
|
@ -168,6 +168,16 @@ typedef void (*uc_add_inline_hook_t)(struct uc_struct *uc, struct hook *hk,
|
|||
// Delete a hook from helper_table
|
||||
typedef void (*uc_del_inline_hook_t)(struct uc_struct *uc, struct hook *hk);
|
||||
|
||||
// Return the size of a CPU context
|
||||
typedef size_t (*uc_context_size_t)(struct uc_struct *uc);
|
||||
|
||||
// Generate a CPU context
|
||||
typedef uc_err (*uc_context_save_t)(struct uc_struct *uc, uc_context *context);
|
||||
|
||||
// Restore a CPU context
|
||||
typedef uc_err (*uc_context_restore_t)(struct uc_struct *uc,
|
||||
uc_context *context);
|
||||
|
||||
// hook list offsets
|
||||
//
|
||||
// The lowest 6 bits are used for hook type index while the others
|
||||
|
@ -285,6 +295,10 @@ struct uc_struct {
|
|||
uc_add_inline_hook_t add_inline_hook;
|
||||
uc_del_inline_hook_t del_inline_hook;
|
||||
|
||||
uc_context_size_t context_size;
|
||||
uc_context_save_t context_save;
|
||||
uc_context_restore_t context_restore;
|
||||
|
||||
/* only 1 cpu in unicorn,
|
||||
do not need current_cpu to handle current running cpu. */
|
||||
CPUState *cpu;
|
||||
|
|
|
@ -350,6 +350,10 @@ typedef enum uc_arm64_reg {
|
|||
|
||||
UC_ARM64_REG_CP_REG,
|
||||
|
||||
//> floating point control and status registers
|
||||
UC_ARM64_REG_FPCR,
|
||||
UC_ARM64_REG_FPSR,
|
||||
|
||||
UC_ARM64_REG_ENDING, // <-- mark the end of the list of registers
|
||||
|
||||
//> alias registers
|
||||
|
|
|
@ -118,8 +118,8 @@ typedef enum uc_mode {
|
|||
UC_MODE_ARM = 0, // ARM mode
|
||||
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
|
||||
// Depreciated, use UC_ARM_CPU_* with uc_ctl instead.
|
||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series.
|
||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM
|
||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series.
|
||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM
|
||||
UC_MODE_ARMBE8 = 1 << 10, // Big-endian data and Little-endian code.
|
||||
// Legacy support for UC1 only.
|
||||
|
||||
|
|
|
@ -86,11 +86,14 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
|||
case UC_ERR_FETCH_UNALIGNED:
|
||||
break;
|
||||
default:
|
||||
if (cc->synchronize_from_tb) {
|
||||
cc->synchronize_from_tb(cpu, last_tb);
|
||||
} else {
|
||||
assert(cc->set_pc);
|
||||
cc->set_pc(cpu, last_tb->pc);
|
||||
// If we receive a quit request, users has sync-ed PC themselves.
|
||||
if (!cpu->uc->quit_request) {
|
||||
if (cc->synchronize_from_tb) {
|
||||
cc->synchronize_from_tb(cpu, last_tb);
|
||||
} else {
|
||||
assert(cc->set_pc);
|
||||
cc->set_pc(cpu, last_tb->pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -595,6 +598,9 @@ int cpu_exec(struct uc_struct *uc, CPUState *cpu)
|
|||
}
|
||||
|
||||
tb = tb_find(cpu, last_tb, tb_exit, cflags);
|
||||
if (unlikely(cpu->exit_request)) {
|
||||
continue;
|
||||
}
|
||||
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit);
|
||||
/* Try to align the host and virtual clocks
|
||||
if the guest is in advance */
|
||||
|
|
|
@ -1451,7 +1451,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
continue;
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, size - uc->size_recur_mem, 0, hook->user_data)))
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, size, 0, hook->user_data)))
|
||||
break;
|
||||
|
||||
// the last callback may already asked to stop emulation
|
||||
|
@ -1466,7 +1466,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
continue;
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, size - uc->size_recur_mem, 0, hook->user_data)))
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, size, 0, hook->user_data)))
|
||||
break;
|
||||
|
||||
// the last callback may already asked to stop emulation
|
||||
|
@ -1484,6 +1484,11 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
if (mr == NULL) {
|
||||
uc->invalid_error = UC_ERR_MAP;
|
||||
cpu_exit(uc->cpu);
|
||||
// XXX(@lazymio): We have to exit early so that the target register won't be overwritten
|
||||
// because qemu might generate tcg code like:
|
||||
// qemu_ld_i64 x0,x1,leq,8 sync: 0 dead: 0 1
|
||||
// where we don't have a change to recover x0 value
|
||||
cpu_loop_exit(uc->cpu);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -1491,6 +1496,8 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
uc->invalid_error = error_code;
|
||||
// printf("***** Invalid fetch (unmapped memory) at " TARGET_FMT_lx "\n", addr);
|
||||
cpu_exit(uc->cpu);
|
||||
// See comments above
|
||||
cpu_loop_exit(uc->cpu);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1518,7 +1525,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
continue;
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, size - uc->size_recur_mem, 0, hook->user_data)))
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, size, 0, hook->user_data)))
|
||||
break;
|
||||
|
||||
// the last callback may already asked to stop emulation
|
||||
|
@ -1533,6 +1540,8 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
uc->invalid_error = UC_ERR_READ_PROT;
|
||||
// printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr);
|
||||
cpu_exit(uc->cpu);
|
||||
// See comments above
|
||||
cpu_loop_exit(uc->cpu);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1546,7 +1555,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
continue;
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, size - uc->size_recur_mem, 0, hook->user_data)))
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, size, 0, hook->user_data)))
|
||||
break;
|
||||
|
||||
// the last callback may already asked to stop emulation
|
||||
|
@ -1561,6 +1570,8 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
uc->invalid_error = UC_ERR_FETCH_PROT;
|
||||
// printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr);
|
||||
cpu_exit(uc->cpu);
|
||||
// See comments above
|
||||
cpu_loop_exit(uc->cpu);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1635,11 +1646,15 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
|
|||
target_ulong addr1, addr2;
|
||||
uint64_t r1, r2;
|
||||
unsigned shift;
|
||||
int old_size;
|
||||
do_unaligned_access:
|
||||
addr1 = addr & ~((target_ulong)size - 1);
|
||||
addr2 = addr1 + size;
|
||||
old_size = uc->size_recur_mem;
|
||||
uc->size_recur_mem = size;
|
||||
r1 = full_load(env, addr1, oi, retaddr);
|
||||
r2 = full_load(env, addr2, oi, retaddr);
|
||||
uc->size_recur_mem = old_size;
|
||||
shift = (addr & (size - 1)) * 8;
|
||||
|
||||
if (memop_big_endian(op)) {
|
||||
|
@ -1977,7 +1992,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
|||
size_t size = memop_size(op);
|
||||
struct hook *hook;
|
||||
bool handled;
|
||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||
MemoryRegion *mr;
|
||||
|
||||
if (!uc->size_recur_mem) { // disabling write callback if in recursive call
|
||||
// Unicorn: callback on memory write
|
||||
|
@ -1994,6 +2009,9 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
|||
}
|
||||
}
|
||||
|
||||
// Load the latest memory mapping.
|
||||
mr = memory_mapping(uc, addr);
|
||||
|
||||
// Unicorn: callback on invalid memory
|
||||
if (mr == NULL) {
|
||||
handled = false;
|
||||
|
@ -2136,6 +2154,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
|||
CPUTLBEntry *entry2;
|
||||
target_ulong page2, tlb_addr2;
|
||||
size_t size2;
|
||||
int old_size;
|
||||
|
||||
do_unaligned_access:
|
||||
/*
|
||||
|
@ -2178,6 +2197,8 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
|||
* This loop must go in the forward direction to avoid issues
|
||||
* with self-modifying code in Windows 64-bit.
|
||||
*/
|
||||
old_size = uc->size_recur_mem;
|
||||
uc->size_recur_mem = size;
|
||||
for (i = 0; i < size; ++i) {
|
||||
uint8_t val8;
|
||||
if (memop_big_endian(op)) {
|
||||
|
@ -2189,6 +2210,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
|||
}
|
||||
helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
|
||||
}
|
||||
uc->size_recur_mem = old_size;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1584,9 +1584,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||
phys_pc = get_page_addr_code(env, pc);
|
||||
|
||||
if (phys_pc == -1) {
|
||||
/* Generate a temporary TB with 1 insn in it */
|
||||
cflags &= ~CF_COUNT_MASK;
|
||||
cflags |= CF_NOCACHE | 1;
|
||||
/* Generate a temporary TB; do not cache */
|
||||
cflags |= CF_NOCACHE;
|
||||
}
|
||||
|
||||
cflags &= ~CF_CLUSTER_MASK;
|
||||
|
|
|
@ -1087,8 +1087,12 @@ RAMBlock *qemu_ram_alloc_from_ptr(struct uc_struct *uc, ram_addr_t size, void *h
|
|||
RAMBlock *new_block;
|
||||
ram_addr_t max_size = size;
|
||||
|
||||
size = HOST_PAGE_ALIGN(uc, size);
|
||||
max_size = HOST_PAGE_ALIGN(uc, max_size);
|
||||
// Don't resize pre-alloced memory as they are given by users.
|
||||
if (!host) {
|
||||
size = HOST_PAGE_ALIGN(uc, size);
|
||||
max_size = HOST_PAGE_ALIGN(uc, max_size);
|
||||
}
|
||||
|
||||
new_block = g_malloc0(sizeof(*new_block));
|
||||
if (new_block == NULL)
|
||||
return NULL;
|
||||
|
|
|
@ -31,41 +31,41 @@
|
|||
* implicit promotion. int and larger types, as well as pointers, can be
|
||||
* converted to a non-qualified type just by applying a binary operator.
|
||||
*/
|
||||
#define typeof_strip_qual(expr) \
|
||||
typeof( \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(expr), bool) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const bool) || \
|
||||
__builtin_types_compatible_p(typeof(expr), volatile bool) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const volatile bool), \
|
||||
(bool)1, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(expr), signed char) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const signed char) || \
|
||||
__builtin_types_compatible_p(typeof(expr), volatile signed char) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const volatile signed char), \
|
||||
(signed char)1, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(expr), unsigned char) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const unsigned char) || \
|
||||
__builtin_types_compatible_p(typeof(expr), volatile unsigned char) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const volatile unsigned char), \
|
||||
(unsigned char)1, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(expr), signed short) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const signed short) || \
|
||||
__builtin_types_compatible_p(typeof(expr), volatile signed short) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const volatile signed short), \
|
||||
(signed short)1, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(typeof(expr), unsigned short) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const unsigned short) || \
|
||||
__builtin_types_compatible_p(typeof(expr), volatile unsigned short) || \
|
||||
__builtin_types_compatible_p(typeof(expr), const volatile unsigned short), \
|
||||
(unsigned short)1, \
|
||||
#define typeof_strip_qual(expr) \
|
||||
__typeof__( \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(expr), bool) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const bool) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), volatile bool) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const volatile bool), \
|
||||
(bool)1, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(expr), signed char) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const signed char) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), volatile signed char) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const volatile signed char), \
|
||||
(signed char)1, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(expr), unsigned char) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const unsigned char) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), volatile unsigned char) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const volatile unsigned char), \
|
||||
(unsigned char)1, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(expr), signed short) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const signed short) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), volatile signed short) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const volatile signed short), \
|
||||
(signed short)1, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(expr), unsigned short) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const unsigned short) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), volatile unsigned short) || \
|
||||
__builtin_types_compatible_p(__typeof__(expr), const volatile unsigned short), \
|
||||
(unsigned short)1, \
|
||||
(expr)+0))))))
|
||||
|
||||
#ifdef __ATOMIC_RELAXED
|
||||
#if defined(__ATOMIC_RELAXED) && !(defined(_MSC_VER) && defined(__clang__))
|
||||
/* For C11 atomic ops */
|
||||
|
||||
/* Sanity check that the size of an atomic operation isn't "overly large".
|
||||
|
|
|
@ -146,7 +146,9 @@ static inline Int128 bswap128(Int128 a)
|
|||
#else /* !CONFIG_INT128 */
|
||||
|
||||
typedef struct Int128 Int128;
|
||||
#if !(defined(_MSC_VER) && defined(__clang__))
|
||||
typedef Int128 __int128_t;
|
||||
#endif
|
||||
|
||||
struct Int128 {
|
||||
uint64_t lo;
|
||||
|
|
|
@ -1708,4 +1708,12 @@
|
|||
#define ppc_dcr_init ppc_dcr_init_ppc
|
||||
#define ppc_cpu_pir ppc_cpu_pir_ppc
|
||||
#define ppc_irq_reset ppc_irq_reset_ppc
|
||||
#define store_booke_tsr store_booke_tsr_ppc
|
||||
#define get_pteg_offset32 get_pteg_offset32_ppc
|
||||
#define ppc_booke_timers_init ppc_booke_timers_init_ppc
|
||||
#define ppc_hash32_handle_mmu_fault ppc_hash32_handle_mmu_fault_ppc
|
||||
#define gen_helper_store_booke_tsr gen_helper_store_booke_tsr_ppc
|
||||
#define gen_helper_store_booke_tcr gen_helper_store_booke_tcr_ppc
|
||||
#define store_booke_tcr store_booke_tcr_ppc
|
||||
#define ppc_hash32_get_phys_page_debug ppc_hash32_get_phys_page_debug_ppc
|
||||
#endif
|
||||
|
|
|
@ -1708,4 +1708,12 @@
|
|||
#define ppc_dcr_init ppc_dcr_init_ppc64
|
||||
#define ppc_cpu_pir ppc_cpu_pir_ppc64
|
||||
#define ppc_irq_reset ppc_irq_reset_ppc64
|
||||
#define store_booke_tsr store_booke_tsr_ppc64
|
||||
#define get_pteg_offset32 get_pteg_offset32_ppc64
|
||||
#define ppc_booke_timers_init ppc_booke_timers_init_ppc64
|
||||
#define ppc_hash32_handle_mmu_fault ppc_hash32_handle_mmu_fault_ppc64
|
||||
#define gen_helper_store_booke_tsr gen_helper_store_booke_tsr_ppc64
|
||||
#define gen_helper_store_booke_tcr gen_helper_store_booke_tcr_ppc64
|
||||
#define store_booke_tcr store_booke_tcr_ppc64
|
||||
#define ppc_hash32_get_phys_page_debug ppc_hash32_get_phys_page_debug_ppc64
|
||||
#endif
|
||||
|
|
|
@ -2188,7 +2188,7 @@ ARMCPU *cpu_arm_init(struct uc_struct *uc)
|
|||
env->uncached_cpsr |= CPSR_E;
|
||||
}
|
||||
|
||||
if (uc->mode & UC_MODE_BIG_ENDIAN && !arm_feature(env, ARM_FEATURE_V7) && !arm_feature(env, ARM_FEATURE_V8)) {
|
||||
if (uc->mode & UC_MODE_BIG_ENDIAN) {
|
||||
// Big endian code access.
|
||||
env->cp15.sctlr_ns |= SCTLR_B;
|
||||
}
|
||||
|
|
|
@ -3098,7 +3098,8 @@ static inline bool arm_sctlr_b(CPUARMState *env)
|
|||
* let linux-user ignore the fact that it conflicts with SCTLR_B.
|
||||
* This lets people run BE32 binaries with "-cpu any".
|
||||
*/
|
||||
!arm_feature(env, ARM_FEATURE_V7) &&
|
||||
// Unicorn: Our hack to support BE32 mode
|
||||
// !arm_feature(env, ARM_FEATURE_V7) &&
|
||||
(env->cp15.sctlr_el[1] & SCTLR_B) != 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -3845,6 +3845,12 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
|||
/* Loads and stores */
|
||||
static void disas_ldst(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_MEM_READ, s->pc_curr) || HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_MEM_WRITE, s->pc_curr)) {
|
||||
// sync PC if there are memory hooks.
|
||||
// TODO: Better granularity by checking ldst type and corresponding hook type
|
||||
gen_a64_set_pc_im(s->uc->tcg_ctx, s->pc_curr);
|
||||
}
|
||||
|
||||
switch (extract32(insn, 24, 6)) {
|
||||
case 0x08: /* Load/store exclusive */
|
||||
disas_ldst_excl(s, insn);
|
||||
|
|
|
@ -225,6 +225,12 @@ static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value)
|
|||
case UC_ARM64_REG_CP_REG:
|
||||
ret = read_cp_reg(env, (uc_arm64_cp_reg *)value);
|
||||
break;
|
||||
case UC_ARM64_REG_FPCR:
|
||||
*(uint32_t *)value = vfp_get_fpcr(env);
|
||||
break;
|
||||
case UC_ARM64_REG_FPSR:
|
||||
*(uint32_t *)value = vfp_get_fpsr(env);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,6 +324,12 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value)
|
|||
case UC_ARM64_REG_CP_REG:
|
||||
ret = write_cp_reg(env, (uc_arm64_cp_reg *)value);
|
||||
break;
|
||||
case UC_ARM64_REG_FPCR:
|
||||
vfp_set_fpcr(env, *(uint32_t *)value);
|
||||
break;
|
||||
case UC_ARM64_REG_FPSR:
|
||||
vfp_set_fpsr(env, *(uint32_t *)value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -621,6 +621,145 @@ static int arm_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static size_t uc_arm_context_size(struct uc_struct *uc)
|
||||
{
|
||||
size_t ret = offsetof(CPUARMState, cpu_watchpoint);
|
||||
ARMCPU *cpu = (ARMCPU *)uc->cpu;
|
||||
CPUARMState *env = (CPUARMState *)&cpu->env;
|
||||
uint32_t nr;
|
||||
|
||||
#define ARM_ENV_CHECK(field) \
|
||||
if (field) { \
|
||||
ret += sizeof(uint32_t) * (nr + 1); \
|
||||
} else { \
|
||||
ret += sizeof(uint32_t); \
|
||||
}
|
||||
|
||||
// /* PMSAv7 MPU */
|
||||
// struct {
|
||||
// uint32_t *drbar;
|
||||
// uint32_t *drsr;
|
||||
// uint32_t *dracr;
|
||||
// uint32_t rnr[M_REG_NUM_BANKS];
|
||||
// } pmsav7;
|
||||
// /* PMSAv8 MPU */
|
||||
// struct {
|
||||
// /* The PMSAv8 implementation also shares some PMSAv7 config
|
||||
// * and state:
|
||||
// * pmsav7.rnr (region number register)
|
||||
// * pmsav7_dregion (number of configured regions)
|
||||
// */
|
||||
// uint32_t *rbar[M_REG_NUM_BANKS];
|
||||
// uint32_t *rlar[M_REG_NUM_BANKS];
|
||||
// uint32_t mair0[M_REG_NUM_BANKS];
|
||||
// uint32_t mair1[M_REG_NUM_BANKS];
|
||||
// } pmsav8;
|
||||
nr = cpu->pmsav7_dregion;
|
||||
ARM_ENV_CHECK(env->pmsav7.drbar)
|
||||
ARM_ENV_CHECK(env->pmsav7.drsr)
|
||||
ARM_ENV_CHECK(env->pmsav7.dracr)
|
||||
ARM_ENV_CHECK(env->pmsav8.rbar[M_REG_NS])
|
||||
ARM_ENV_CHECK(env->pmsav8.rbar[M_REG_S])
|
||||
ARM_ENV_CHECK(env->pmsav8.rlar[M_REG_NS])
|
||||
ARM_ENV_CHECK(env->pmsav8.rlar[M_REG_S])
|
||||
|
||||
// /* v8M SAU */
|
||||
// struct {
|
||||
// uint32_t *rbar;
|
||||
// uint32_t *rlar;
|
||||
// uint32_t rnr;
|
||||
// uint32_t ctrl;
|
||||
// } sau;
|
||||
nr = cpu->sau_sregion;
|
||||
ARM_ENV_CHECK(env->sau.rbar)
|
||||
ARM_ENV_CHECK(env->sau.rlar)
|
||||
#undef ARM_ENV_CHECK
|
||||
// These fields are never used:
|
||||
// void *nvic;
|
||||
// const struct arm_boot_info *boot_info;
|
||||
// void *gicv3state;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uc_err uc_arm_context_save(struct uc_struct *uc, uc_context *context)
|
||||
{
|
||||
char *p = NULL;
|
||||
ARMCPU *cpu = (ARMCPU *)uc->cpu;
|
||||
CPUARMState *env = (CPUARMState *)&cpu->env;
|
||||
uint32_t nr = 0;
|
||||
|
||||
#define ARM_ENV_SAVE(field) \
|
||||
if (!field) { \
|
||||
*(uint32_t *)p = 0; \
|
||||
p += sizeof(uint32_t); \
|
||||
} else { \
|
||||
*(uint32_t *)p = nr; \
|
||||
p += sizeof(uint32_t); \
|
||||
memcpy(p, (void *)field, sizeof(uint32_t) * nr); \
|
||||
p += sizeof(uint32_t) * nr; \
|
||||
}
|
||||
p = context->data;
|
||||
memcpy(p, uc->cpu->env_ptr, uc->cpu_context_size);
|
||||
p += uc->cpu_context_size;
|
||||
|
||||
nr = cpu->pmsav7_dregion;
|
||||
ARM_ENV_SAVE(env->pmsav7.drbar)
|
||||
ARM_ENV_SAVE(env->pmsav7.drsr)
|
||||
ARM_ENV_SAVE(env->pmsav7.dracr)
|
||||
ARM_ENV_SAVE(env->pmsav8.rbar[M_REG_NS])
|
||||
ARM_ENV_SAVE(env->pmsav8.rbar[M_REG_S])
|
||||
ARM_ENV_SAVE(env->pmsav8.rlar[M_REG_NS])
|
||||
ARM_ENV_SAVE(env->pmsav8.rlar[M_REG_S])
|
||||
|
||||
nr = cpu->sau_sregion;
|
||||
ARM_ENV_SAVE(env->sau.rbar)
|
||||
ARM_ENV_SAVE(env->sau.rlar)
|
||||
|
||||
#undef ARM_ENV_SAVE
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
static uc_err uc_arm_context_restore(struct uc_struct *uc, uc_context *context)
|
||||
{
|
||||
char *p = NULL;
|
||||
ARMCPU *cpu = (ARMCPU *)uc->cpu;
|
||||
CPUARMState *env = (CPUARMState *)&cpu->env;
|
||||
uint32_t nr, ctx_nr;
|
||||
|
||||
#define ARM_ENV_RESTORE(field) \
|
||||
ctx_nr = *(uint32_t *)p; \
|
||||
if (ctx_nr != 0) { \
|
||||
p += sizeof(uint32_t); \
|
||||
if (field && ctx_nr == nr) { \
|
||||
memcpy(field, p, sizeof(uint32_t) * ctx_nr); \
|
||||
} \
|
||||
p += sizeof(uint32_t) * ctx_nr; \
|
||||
} else { \
|
||||
p += sizeof(uint32_t); \
|
||||
}
|
||||
|
||||
p = context->data;
|
||||
memcpy(uc->cpu->env_ptr, p, uc->cpu_context_size);
|
||||
p += uc->cpu_context_size;
|
||||
|
||||
nr = cpu->pmsav7_dregion;
|
||||
ARM_ENV_RESTORE(env->pmsav7.drbar)
|
||||
ARM_ENV_RESTORE(env->pmsav7.drsr)
|
||||
ARM_ENV_RESTORE(env->pmsav7.dracr)
|
||||
ARM_ENV_RESTORE(env->pmsav8.rbar[M_REG_NS])
|
||||
ARM_ENV_RESTORE(env->pmsav8.rbar[M_REG_S])
|
||||
ARM_ENV_RESTORE(env->pmsav8.rlar[M_REG_NS])
|
||||
ARM_ENV_RESTORE(env->pmsav8.rlar[M_REG_S])
|
||||
|
||||
nr = cpu->sau_sregion;
|
||||
ARM_ENV_RESTORE(env->sau.rbar)
|
||||
ARM_ENV_RESTORE(env->sau.rlar)
|
||||
|
||||
#undef ARM_ENV_RESTORE
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
void arm_uc_init(struct uc_struct *uc)
|
||||
{
|
||||
uc->reg_read = arm_reg_read;
|
||||
|
@ -634,5 +773,8 @@ void arm_uc_init(struct uc_struct *uc)
|
|||
uc->cpus_init = arm_cpus_init;
|
||||
uc->opcode_hook_invalidate = arm_opcode_hook_invalidate;
|
||||
uc->cpu_context_size = offsetof(CPUARMState, cpu_watchpoint);
|
||||
uc->context_size = uc_arm_context_size;
|
||||
uc->context_save = uc_arm_context_save;
|
||||
uc->context_restore = uc_arm_context_restore;
|
||||
uc_common_init(uc);
|
||||
}
|
||||
|
|
|
@ -3378,6 +3378,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||
if (is_xmm)
|
||||
reg |= rex_r;
|
||||
mod = (modrm >> 6) & 3;
|
||||
/* VEX.L (256 bit) encodings are not supported */
|
||||
if (s->vex_l != 0) {
|
||||
goto illegal_op; // perhaps it should be unknown_op?
|
||||
}
|
||||
if (sse_fn_epp == SSE_SPECIAL) {
|
||||
b |= (b1 << 8);
|
||||
switch(b) {
|
||||
|
|
|
@ -289,9 +289,9 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value,
|
|||
case UC_X86_REG_XMM6:
|
||||
case UC_X86_REG_XMM7: {
|
||||
float64 *dst = (float64 *)value;
|
||||
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||
dst[0] = reg->_d[0];
|
||||
dst[1] = reg->_d[1];
|
||||
ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||
dst[0] = reg->ZMM_Q(0);
|
||||
dst[1] = reg->ZMM_Q(1);
|
||||
return;
|
||||
}
|
||||
case UC_X86_REG_ST0:
|
||||
|
@ -323,10 +323,10 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value,
|
|||
case UC_X86_REG_YMM14:
|
||||
case UC_X86_REG_YMM15: {
|
||||
float64 *dst = (float64 *)value;
|
||||
XMMReg *lo_reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
|
||||
ZMMReg *lo_reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
|
||||
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
|
||||
dst[0] = lo_reg->_d[0];
|
||||
dst[1] = lo_reg->_d[1];
|
||||
dst[0] = lo_reg->ZMM_Q(0);
|
||||
dst[1] = lo_reg->ZMM_Q(1);
|
||||
dst[2] = hi_reg->_d[0];
|
||||
dst[3] = hi_reg->_d[1];
|
||||
return;
|
||||
|
@ -828,9 +828,9 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value,
|
|||
case UC_X86_REG_XMM14:
|
||||
case UC_X86_REG_XMM15: {
|
||||
float64 *dst = (float64 *)value;
|
||||
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||
dst[0] = reg->_d[0];
|
||||
dst[1] = reg->_d[1];
|
||||
ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||
dst[0] = reg->ZMM_Q(0);
|
||||
dst[1] = reg->ZMM_Q(1);
|
||||
break;
|
||||
}
|
||||
case UC_X86_REG_FS_BASE:
|
||||
|
@ -896,9 +896,9 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value,
|
|||
case UC_X86_REG_XMM6:
|
||||
case UC_X86_REG_XMM7: {
|
||||
float64 *src = (float64 *)value;
|
||||
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||
reg->_d[0] = src[0];
|
||||
reg->_d[1] = src[1];
|
||||
ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||
reg->ZMM_Q(0) = src[0];
|
||||
reg->ZMM_Q(1) = src[1];
|
||||
return 0;
|
||||
}
|
||||
case UC_X86_REG_ST0:
|
||||
|
@ -930,10 +930,12 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value,
|
|||
case UC_X86_REG_YMM14:
|
||||
case UC_X86_REG_YMM15: {
|
||||
float64 *src = (float64 *)value;
|
||||
XMMReg *lo_reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
|
||||
ZMMReg *lo_reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
|
||||
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
|
||||
lo_reg->_d[0] = src[0];
|
||||
lo_reg->_d[1] = src[1];
|
||||
lo_reg->ZMM_Q(0) = src[0];
|
||||
lo_reg->ZMM_Q(1) = src[1];
|
||||
// YMM is not supported by QEMU at all
|
||||
// As of qemu 5.0.1, ymmh_regs is nowhere used.
|
||||
hi_reg->_d[0] = src[2];
|
||||
hi_reg->_d[1] = src[3];
|
||||
return 0;
|
||||
|
@ -1471,9 +1473,9 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value,
|
|||
case UC_X86_REG_XMM14:
|
||||
case UC_X86_REG_XMM15: {
|
||||
float64 *src = (float64 *)value;
|
||||
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||
reg->_d[0] = src[0];
|
||||
reg->_d[1] = src[1];
|
||||
ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||
reg->ZMM_Q(0) = src[0];
|
||||
reg->ZMM_Q(1) = src[1];
|
||||
break;
|
||||
}
|
||||
case UC_X86_REG_FS_BASE:
|
||||
|
|
|
@ -1061,7 +1061,11 @@ void helper_store_msr(CPUPPCState *env, target_ulong val)
|
|||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
#if defined(_MSC_VER) && defined(__clang__)
|
||||
void helper_pminsn(CPUPPCState *env, uint32_t insn)
|
||||
#else
|
||||
void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
|
||||
#endif
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
|
|
|
@ -1603,7 +1603,7 @@ static void gen_xxspltw(DisasContext *ctx)
|
|||
tofs = vsr_full_offset(rt);
|
||||
bofs = vsr_full_offset(rb);
|
||||
bofs += uim << MO_32;
|
||||
#ifndef HOST_WORDS_BIG_ENDIAN
|
||||
#ifndef HOST_WORDS_BIGENDIAN
|
||||
bofs ^= 8 | 4;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ static void ppc_release(void *ctx)
|
|||
int i;
|
||||
TCGContext *tcg_ctx = (TCGContext *)ctx;
|
||||
PowerPCCPU *cpu = (PowerPCCPU *)tcg_ctx->uc->cpu;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
CPUTLBDesc *d = cpu->neg.tlb.d;
|
||||
CPUTLBDescFast *f = cpu->neg.tlb.f;
|
||||
CPUTLBDesc *desc;
|
||||
|
@ -132,6 +133,20 @@ static void ppc_release(void *ctx)
|
|||
|
||||
// g_free(tcg_ctx->tb_ctx.tbs);
|
||||
|
||||
if (env->nb_tlb != 0) {
|
||||
switch (env->tlb_type) {
|
||||
case TLB_6XX:
|
||||
g_free(env->tlb.tlb6);
|
||||
break;
|
||||
case TLB_EMB:
|
||||
g_free(env->tlb.tlbe);
|
||||
break;
|
||||
case TLB_MAS:
|
||||
g_free(env->tlb.tlbm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ppc_cpu_instance_finalize(tcg_ctx->uc->cpu);
|
||||
ppc_cpu_unrealize(tcg_ctx->uc->cpu);
|
||||
}
|
||||
|
@ -292,7 +307,7 @@ static void reg_write(CPUPPCState *env, unsigned int regid, const void *value)
|
|||
break;
|
||||
case UC_PPC_REG_CR:
|
||||
val = *(uint32_t *)value;
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (i = 7; i >= 0; i--) {
|
||||
env->crf[i] = val & 0b1111;
|
||||
val >>= 4;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||
DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64)
|
||||
DEF_HELPER_1(uc_tricore_exit,void, env)
|
||||
|
||||
/* Arithmetic */
|
||||
DEF_HELPER_3(add_ssov, i32, env, i32, i32)
|
||||
|
|
|
@ -2793,3 +2793,12 @@ uint32_t helper_psw_read(CPUTriCoreState *env)
|
|||
{
|
||||
return psw_read(env);
|
||||
}
|
||||
|
||||
void helper_uc_tricore_exit(CPUTriCoreState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->exception_index = EXCP_HLT;
|
||||
cs->halted = 1;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
|
@ -33,6 +33,11 @@
|
|||
#include "exec/translator.h"
|
||||
#include "exec/gen-icount.h"
|
||||
|
||||
/*
|
||||
* Unicorn: Special disas state for exiting in the middle of tb.
|
||||
*/
|
||||
#define DISAS_UC_EXIT DISAS_TARGET_6
|
||||
|
||||
static const char *regnames_a[] = {
|
||||
"a0" , "a1" , "a2" , "a3" , "a4" , "a5" ,
|
||||
"a6" , "a7" , "a8" , "a9" , "sp" , "a11" ,
|
||||
|
@ -9227,11 +9232,7 @@ static void tricore_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (uc_addr_is_exit(uc, ctx->base.pc_next)) {
|
||||
gen_helper_rfe(tcg_ctx, tcg_ctx->cpu_env);
|
||||
tcg_gen_exit_tb(tcg_ctx, NULL, 0);
|
||||
cpu->exception_index = EXCP_HLT;
|
||||
cpu->halted = 1;
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
ctx->base.is_jmp = DISAS_UC_EXIT;
|
||||
} else {
|
||||
insn_lo = cpu_lduw_code(env, ctx->base.pc_next);
|
||||
is_16bit = tricore_insn_is_16bit(insn_lo);
|
||||
|
@ -9239,6 +9240,9 @@ static void tricore_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|||
insn_size = is_16bit ? 2 : 4;
|
||||
// Unicorn: trace this instruction on request
|
||||
if (HOOK_EXISTS_BOUNDED(ctx->uc, UC_HOOK_CODE, ctx->base.pc_next)) {
|
||||
// Sync PC in advance
|
||||
gen_save_pc(ctx, ctx->base.pc_next);
|
||||
|
||||
gen_uc_tracecode(tcg_ctx, insn_size, UC_HOOK_CODE_IDX, ctx->uc,
|
||||
ctx->base.pc_next);
|
||||
// the callback might want to stop emulation immediately
|
||||
|
@ -9282,6 +9286,10 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|||
case DISAS_TOO_MANY:
|
||||
gen_goto_tb(ctx, 0, ctx->base.pc_next);
|
||||
break;
|
||||
case DISAS_UC_EXIT:
|
||||
gen_save_pc(ctx, ctx->base.pc_next);
|
||||
gen_helper_uc_tricore_exit(ctx->uc->tcg_ctx, ctx->uc->tcg_ctx->cpu_env);
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
break;
|
||||
default:
|
||||
|
@ -9371,4 +9379,4 @@ void tricore_tcg_init(struct uc_struct *uc)
|
|||
tcg_ctx->cpu_PSW_SAV = tcg_global_mem_new(uc->tcg_ctx, tcg_ctx->cpu_env,
|
||||
offsetof(CPUTriCoreState, PSW_USB_SAV),
|
||||
"PSW_SAV");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -263,6 +263,25 @@ static int tricore_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tricore_release(void *ctx)
|
||||
{
|
||||
int i;
|
||||
TCGContext *tcg_ctx = (TCGContext *)ctx;
|
||||
TriCoreCPU *cpu = (TriCoreCPU *)tcg_ctx->uc->cpu;
|
||||
CPUTLBDesc *d = cpu->neg.tlb.d;
|
||||
CPUTLBDescFast *f = cpu->neg.tlb.f;
|
||||
CPUTLBDesc *desc;
|
||||
CPUTLBDescFast *fast;
|
||||
|
||||
release_common(ctx);
|
||||
for (i = 0; i < NB_MMU_MODES; i++) {
|
||||
desc = &(d[i]);
|
||||
fast = &(f[i]);
|
||||
g_free(desc->iotlb);
|
||||
g_free(fast->table);
|
||||
}
|
||||
}
|
||||
|
||||
void tricore_uc_init(struct uc_struct *uc)
|
||||
{
|
||||
uc->reg_read = tricore_reg_read;
|
||||
|
@ -271,6 +290,7 @@ void tricore_uc_init(struct uc_struct *uc)
|
|||
uc->set_pc = tricore_set_pc;
|
||||
uc->get_pc = tricore_get_pc;
|
||||
uc->cpus_init = tricore_cpus_init;
|
||||
uc->release = tricore_release;
|
||||
uc->cpu_context_size = offsetof(CPUTriCoreState, end_reset_fields);
|
||||
uc_common_init(uc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1286,4 +1286,5 @@
|
|||
#define helper_pack helper_pack_tricore
|
||||
#define gen_intermediate_code gen_intermediate_code_tricore
|
||||
#define restore_state_to_opc restore_state_to_opc_tricore
|
||||
#define helper_uc_tricore_exit helper_uc_tricore_exit_tricore
|
||||
#endif
|
||||
|
|
|
@ -243,7 +243,8 @@ static void test_uc_ctl_tb_cache()
|
|||
|
||||
// Now we request cache for all TBs.
|
||||
for (int i = 0; i < TB_COUNT; i++) {
|
||||
err = uc_ctl_request_cache(uc, ADDRESS + i * TCG_MAX_INSNS, &tb);
|
||||
err = uc_ctl_request_cache(uc, (uint64_t)(ADDRESS + i * TCG_MAX_INSNS),
|
||||
&tb);
|
||||
printf(">>> TB is cached at 0x%" PRIx64 " which has %" PRIu16
|
||||
" instructions with %" PRIu16 " bytes.\n",
|
||||
tb.pc, tb.icount, tb.size);
|
||||
|
@ -258,8 +259,8 @@ static void test_uc_ctl_tb_cache()
|
|||
|
||||
// Now we clear cache for all TBs.
|
||||
for (int i = 0; i < TB_COUNT; i++) {
|
||||
err = uc_ctl_remove_cache(uc, ADDRESS + i * TCG_MAX_INSNS,
|
||||
ADDRESS + i * TCG_MAX_INSNS + 1);
|
||||
err = uc_ctl_remove_cache(uc, (uint64_t)(ADDRESS + i * TCG_MAX_INSNS),
|
||||
(uint64_t)(ADDRESS + i * TCG_MAX_INSNS + 1));
|
||||
if (err) {
|
||||
printf("Failed on uc_ctl() with error returned: %u\n", err);
|
||||
return;
|
||||
|
|
|
@ -1404,7 +1404,7 @@ static void test_i386_hook_mem_invalid()
|
|||
uc_err err;
|
||||
|
||||
printf("===================================\n");
|
||||
printf("Emulate i386 code that tiggers invalid memory read/write.\n");
|
||||
printf("Emulate i386 code that triggers invalid memory read/write.\n");
|
||||
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||
if (err) {
|
||||
|
|
|
@ -6264,6 +6264,14 @@ ppc_dcr_register \
|
|||
ppc_dcr_init \
|
||||
ppc_cpu_pir \
|
||||
ppc_irq_reset \
|
||||
store_booke_tsr \
|
||||
get_pteg_offset32 \
|
||||
ppc_booke_timers_init \
|
||||
ppc_hash32_handle_mmu_fault \
|
||||
gen_helper_store_booke_tsr \
|
||||
gen_helper_store_booke_tcr \
|
||||
store_booke_tcr \
|
||||
ppc_hash32_get_phys_page_debug \
|
||||
"
|
||||
|
||||
ppc64_SYMBOLS=${ppc_SYMBOLS}
|
||||
|
@ -6284,6 +6292,7 @@ helper_fmsub \
|
|||
helper_pack \
|
||||
gen_intermediate_code \
|
||||
restore_state_to_opc \
|
||||
helper_uc_tricore_exit \
|
||||
"
|
||||
|
||||
ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore"
|
||||
|
|
|
@ -47,12 +47,37 @@ static void test_vmovdqu(void)
|
|||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
/* https://github.com/unicorn-engine/unicorn/issues/1656 */
|
||||
static void test_vex_l(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_err err;
|
||||
|
||||
/* vmovdqu ymm1, [rcx] */
|
||||
char code[] = { '\xC5', '\xFE', '\x6F', '\x09' };
|
||||
|
||||
/* initialize memory and run emulation */
|
||||
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||
OK(uc_mem_map(uc, 0, 2 * 1024 * 1024, UC_PROT_ALL));
|
||||
|
||||
OK(uc_mem_write(uc, 0, code, sizeof(code) / sizeof(code[0])));
|
||||
|
||||
err = uc_emu_start(uc, 0, sizeof(code) / sizeof(code[0]), 0, 0);
|
||||
if(err != UC_ERR_INSN_INVALID) {
|
||||
fprintf(stderr, "%s", uc_strerror(err));
|
||||
assert(false);
|
||||
}
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Add more vex prefixed instructions
|
||||
Suggestions: vxorpd, vxorps, vandpd, ... */
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
test_vmovdqu();
|
||||
test_vex_l();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
// Copy fron boost 1.43.0
|
||||
|
||||
// Copyright 2005 Caleb Epstein
|
||||
// Copyright 2006 John Maddock
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompany-
|
||||
// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997
|
||||
* Silicon Graphics Computer Systems, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. Silicon Graphics makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright notice reproduced from <boost/detail/limits.hpp>, from
|
||||
* which this code was originally taken.
|
||||
*
|
||||
* Modified by Caleb Epstein to use <endian.h> with GNU libc and to
|
||||
* defined the BOOST_ENDIAN macro.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_DETAIL_ENDIAN_HPP
|
||||
#define BOOST_DETAIL_ENDIAN_HPP
|
||||
|
||||
// GNU libc offers the helpful header <endian.h> which defines
|
||||
// __BYTE_ORDER
|
||||
|
||||
#if defined (__GLIBC__)
|
||||
# include <endian.h>
|
||||
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
# define BOOST_LITTLE_ENDIAN
|
||||
# elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
# define BOOST_BIG_ENDIAN
|
||||
# elif (__BYTE_ORDER == __PDP_ENDIAN)
|
||||
# define BOOST_PDP_ENDIAN
|
||||
# else
|
||||
# error Unknown machine endianness detected.
|
||||
# endif
|
||||
# define BOOST_BYTE_ORDER __BYTE_ORDER
|
||||
#elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
|
||||
# define BOOST_BIG_ENDIAN
|
||||
# define BOOST_BYTE_ORDER 4321
|
||||
#elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
|
||||
# define BOOST_LITTLE_ENDIAN
|
||||
# define BOOST_BYTE_ORDER 1234
|
||||
#elif defined(__sparc) || defined(__sparc__) \
|
||||
|| defined(_POWER) || defined(__powerpc__) \
|
||||
|| defined(__ppc__) || defined(__hpux) || defined(__hppa) \
|
||||
|| defined(_MIPSEB) || defined(_POWER) \
|
||||
|| defined(__s390__)
|
||||
# define BOOST_BIG_ENDIAN
|
||||
# define BOOST_BYTE_ORDER 4321
|
||||
#elif defined(__i386__) || defined(__alpha__) \
|
||||
|| defined(__ia64) || defined(__ia64__) \
|
||||
|| defined(_M_IX86) || defined(_M_IA64) \
|
||||
|| defined(_M_ALPHA) || defined(__amd64) \
|
||||
|| defined(__amd64__) || defined(_M_AMD64) \
|
||||
|| defined(__x86_64) || defined(__x86_64__) \
|
||||
|| defined(_M_X64) || defined(__bfin__)
|
||||
|
||||
# define BOOST_LITTLE_ENDIAN
|
||||
# define BOOST_BYTE_ORDER 1234
|
||||
#else
|
||||
# error The file boost/detail/endian.hpp needs to be set up for your CPU type.
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -164,9 +164,9 @@ static void test_arm_thumb_ite(void)
|
|||
OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3));
|
||||
|
||||
OK(uc_mem_map(uc, r_sp, 0x1000, UC_PROT_ALL));
|
||||
r_r2 = 0x68;
|
||||
r_r2 = LEINT32(0x68);
|
||||
OK(uc_mem_write(uc, r_sp, &r_r2, 4));
|
||||
r_r2 = 0x4d;
|
||||
r_r2 = LEINT32(0x4d);
|
||||
OK(uc_mem_write(uc, r_sp + 4, &r_r2, 4));
|
||||
|
||||
OK(uc_hook_add(uc, &hook, UC_HOOK_CODE, test_arm_thumb_ite_count_callback,
|
||||
|
@ -396,7 +396,7 @@ static void test_arm_v8(void)
|
|||
{
|
||||
char code[] = "\xd0\xe8\xff\x17"; // LDAEXD.W R1, [R0]
|
||||
uc_engine *uc;
|
||||
uint32_t r_r1 = 0xdeadbeef;
|
||||
uint32_t r_r1 = LEINT32(0xdeadbeef);
|
||||
uint32_t r_r0;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1,
|
||||
|
@ -751,6 +751,70 @@ static void test_armeb_ldrb(void)
|
|||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_arm_context_save(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_engine *uc2;
|
||||
char code[] = "\x83\xb0"; // sub sp, #0xc
|
||||
uc_context *ctx;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1,
|
||||
UC_CPU_ARM_CORTEX_R5);
|
||||
|
||||
OK(uc_context_alloc(uc, &ctx));
|
||||
OK(uc_context_save(uc, ctx));
|
||||
OK(uc_context_restore(uc, ctx));
|
||||
|
||||
uc_common_setup(&uc2, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1,
|
||||
UC_CPU_ARM_CORTEX_A7); // Note the different CPU model
|
||||
|
||||
OK(uc_context_restore(uc2, ctx));
|
||||
|
||||
OK(uc_context_free(ctx));
|
||||
OK(uc_close(uc));
|
||||
OK(uc_close(uc2));
|
||||
}
|
||||
|
||||
static void test_arm_thumb2(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
// MOVS R0, #0x24
|
||||
// AND.W R0, R0, #4
|
||||
char code[] = "\x24\x20\x00\xF0\x04\x00";
|
||||
uint32_t r_r0;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_LITTLE_ENDIAN,
|
||||
code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_R5);
|
||||
|
||||
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0));
|
||||
|
||||
TEST_CHECK(r_r0 == 0x4);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_armeb_be32_thumb2(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
// MOVS R0, #0x24
|
||||
// AND.W R0, R0, #4
|
||||
char code[] = "\x20\x24\xF0\x00\x00\x04";
|
||||
uint32_t r_r0;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_BIG_ENDIAN, code,
|
||||
sizeof(code) - 1, UC_CPU_ARM_CORTEX_R5);
|
||||
|
||||
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0));
|
||||
|
||||
TEST_CHECK(r_r0 == 0x4);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {{"test_arm_nop", test_arm_nop},
|
||||
{"test_arm_thumb_sub", test_arm_thumb_sub},
|
||||
{"test_armeb_sub", test_armeb_sub},
|
||||
|
@ -773,4 +837,7 @@ TEST_LIST = {{"test_arm_nop", test_arm_nop},
|
|||
{"test_arm_be_cpsr_sctlr", test_arm_be_cpsr_sctlr},
|
||||
{"test_arm_switch_endian", test_arm_switch_endian},
|
||||
{"test_armeb_ldrb", test_armeb_ldrb},
|
||||
{"test_arm_context_save", test_arm_context_save},
|
||||
{"test_arm_thumb2", test_arm_thumb2},
|
||||
{"test_armeb_be32_thumb2", test_armeb_be32_thumb2},
|
||||
{NULL, NULL}};
|
|
@ -1,10 +1,14 @@
|
|||
#include "acutest.h"
|
||||
#include "unicorn/unicorn.h"
|
||||
#include "unicorn_test.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const uint64_t code_start = 0x1000;
|
||||
const uint64_t code_len = 0x4000;
|
||||
|
||||
static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode,
|
||||
const char *code, uint64_t size, uc_cpu_arm cpu)
|
||||
const char *code, uint64_t size, uc_cpu_arm64 cpu)
|
||||
{
|
||||
OK(uc_open(arch, mode, uc));
|
||||
OK(uc_ctl_set_cpu_model(*uc, cpu));
|
||||
|
@ -133,7 +137,7 @@ static void test_arm64_v8_pac(void)
|
|||
|
||||
OK(uc_mem_read(uc, 0x40000, (void *)&mem, 8));
|
||||
|
||||
TEST_CHECK(mem == r_x8);
|
||||
TEST_CHECK(LEINT64(mem) == r_x8);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
@ -291,6 +295,83 @@ static void test_arm64_correct_address_in_long_jump_hook(void)
|
|||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_arm64_block_sync_pc_cb(uc_engine *uc, uint64_t addr,
|
||||
uint32_t size, void *data)
|
||||
{
|
||||
uint64_t val = code_start;
|
||||
bool first = *(bool *)data;
|
||||
if (first) {
|
||||
OK(uc_reg_write(uc, UC_ARM64_REG_PC, (void *)&val));
|
||||
*(bool *)data = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_arm64_block_sync_pc(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
// add x0, x0, #1234;bl t;t:mov x1, #5678;
|
||||
const char code[] = "\x00\x48\x13\x91\x01\x00\x00\x94\xc1\xc5\x82\xd2";
|
||||
uc_hook hk;
|
||||
uint64_t x0;
|
||||
bool data = true;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_ARM64, UC_MODE_ARM, code, sizeof(code) - 1,
|
||||
UC_CPU_ARM64_A72);
|
||||
OK(uc_hook_add(uc, &hk, UC_HOOK_BLOCK, test_arm64_block_sync_pc_cb,
|
||||
(void *)&data, code_start + 8, code_start + 12));
|
||||
|
||||
x0 = 0;
|
||||
OK(uc_reg_write(uc, UC_ARM64_REG_X0, (void *)&x0));
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X0, (void *)&x0));
|
||||
|
||||
TEST_CHECK(x0 == (1234 * 2));
|
||||
|
||||
OK(uc_hook_del(uc, hk));
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static bool
|
||||
test_arm64_block_invalid_mem_read_write_sync_cb(uc_engine *uc, int type,
|
||||
uint64_t address, int size,
|
||||
int64_t value, void *user_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_arm64_block_invalid_mem_read_write_sync(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
// mov x0, #1
|
||||
// mov x1, #2
|
||||
// ldr x0, [x1]
|
||||
const char code[] = "\x20\x00\x80\xd2\x41\x00\x80\xd2\x20\x00\x40\xf9";
|
||||
uint64_t r_pc, r_x0, r_x1;
|
||||
uc_hook hk;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_ARM64, UC_MODE_ARM, code, sizeof(code) - 1,
|
||||
UC_CPU_ARM64_A72);
|
||||
|
||||
OK(uc_hook_add(uc, &hk, UC_HOOK_MEM_READ,
|
||||
test_arm64_block_invalid_mem_read_write_sync_cb, NULL, 1,
|
||||
0));
|
||||
|
||||
uc_assert_err(
|
||||
UC_ERR_READ_UNMAPPED,
|
||||
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_PC, &r_pc));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X0, &r_x0));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X1, &r_x1));
|
||||
|
||||
TEST_CHECK(r_pc == code_start + 8);
|
||||
TEST_CHECK(r_x0 == 1);
|
||||
TEST_CHECK(r_x1 == 2);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {{"test_arm64_until", test_arm64_until},
|
||||
{"test_arm64_code_patching", test_arm64_code_patching},
|
||||
{"test_arm64_code_patching_count", test_arm64_code_patching_count},
|
||||
|
@ -301,4 +382,7 @@ TEST_LIST = {{"test_arm64_until", test_arm64_until},
|
|||
test_arm64_correct_address_in_small_jump_hook},
|
||||
{"test_arm64_correct_address_in_long_jump_hook",
|
||||
test_arm64_correct_address_in_long_jump_hook},
|
||||
{"test_arm64_block_sync_pc", test_arm64_block_sync_pc},
|
||||
{"test_arm64_block_invalid_mem_read_write_sync",
|
||||
test_arm64_block_invalid_mem_read_write_sync},
|
||||
{NULL, NULL}};
|
||||
|
|
|
@ -110,14 +110,14 @@ static void test_uc_ctl_exits(void)
|
|||
r_eax = 0;
|
||||
r_ebx = 0;
|
||||
OK(uc_reg_write(uc, UC_X86_REG_EAX, &r_eax));
|
||||
OK(uc_reg_write(uc, UC_X86_REG_EAX, &r_ebx));
|
||||
OK(uc_reg_write(uc, UC_X86_REG_EBX, &r_ebx));
|
||||
|
||||
// Run two times.
|
||||
OK(uc_emu_start(uc, code_start, 0, 0, 0));
|
||||
OK(uc_emu_start(uc, code_start, 0, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_X86_REG_EAX, &r_eax));
|
||||
OK(uc_reg_read(uc, UC_X86_REG_EAX, &r_ebx));
|
||||
OK(uc_reg_read(uc, UC_X86_REG_EBX, &r_ebx));
|
||||
|
||||
TEST_CHECK(r_eax == 1);
|
||||
TEST_CHECK(r_ebx == 1);
|
||||
|
@ -175,6 +175,8 @@ static void test_uc_ctl_tb_cache(void)
|
|||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
// Test requires UC_ARCH_ARM.
|
||||
#ifdef UNICORN_HAS_ARM
|
||||
static void test_uc_ctl_change_page_size(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
|
@ -191,7 +193,10 @@ static void test_uc_ctl_change_page_size(void)
|
|||
OK(uc_close(uc));
|
||||
OK(uc_close(uc2));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test requires UC_ARCH_ARM.
|
||||
#ifdef UNICORN_HAS_ARM
|
||||
// Copy from test_arm.c but with new API.
|
||||
static void test_uc_ctl_arm_cpu(void)
|
||||
{
|
||||
|
@ -226,6 +231,7 @@ static void test_uc_ctl_arm_cpu(void)
|
|||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void test_uc_hook_cached_cb(uc_engine *uc, uint64_t addr, size_t size,
|
||||
void *user_data)
|
||||
|
@ -245,15 +251,22 @@ static void test_uc_hook_cached_uaf(void)
|
|||
uc_hook h;
|
||||
uint64_t count = 0;
|
||||
#ifndef _WIN32
|
||||
void *callback = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
// Apple Silicon does not allow RWX pages.
|
||||
void *callback = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
TEST_CHECK(callback != (void *)-1);
|
||||
#else
|
||||
void *callback = VirtualAlloc(NULL, 4096, MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
TEST_CHECK(callback != NULL);
|
||||
#endif
|
||||
|
||||
memcpy(callback, (void *)test_uc_hook_cached_cb, 4096);
|
||||
|
||||
#ifndef _WIN32
|
||||
TEST_CHECK(mprotect(callback, 4096, PROT_READ | PROT_EXEC) == 0);
|
||||
#endif
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||
|
||||
OK(uc_hook_add(uc, &h, UC_HOOK_CODE, (void *)callback, (void *)&count, 1,
|
||||
|
@ -267,8 +280,16 @@ static void test_uc_hook_cached_uaf(void)
|
|||
// This will clear deleted hooks and SHOULD clear cache.
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
#ifndef _WIN32
|
||||
TEST_CHECK(mprotect(callback, 4096, PROT_READ | PROT_WRITE) == 0);
|
||||
#endif
|
||||
|
||||
memset(callback, 0, 4096);
|
||||
|
||||
#ifndef _WIN32
|
||||
TEST_CHECK(mprotect(callback, 4096, PROT_READ | PROT_EXEC) == 0);
|
||||
#endif
|
||||
|
||||
// Now hooks are deleted and thus this will trigger a UAF
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
|
@ -289,7 +310,9 @@ TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode},
|
|||
{"test_uc_ctl_time_out", test_uc_ctl_time_out},
|
||||
{"test_uc_ctl_exits", test_uc_ctl_exits},
|
||||
{"test_uc_ctl_tb_cache", test_uc_ctl_tb_cache},
|
||||
#ifdef UNICORN_HAS_ARM
|
||||
{"test_uc_ctl_change_page_size", test_uc_ctl_change_page_size},
|
||||
{"test_uc_ctl_arm_cpu", test_uc_ctl_arm_cpu},
|
||||
#endif
|
||||
{"test_uc_hook_cached_uaf", test_uc_hook_cached_uaf},
|
||||
{NULL, NULL}};
|
||||
{NULL, NULL}};
|
||||
|
|
|
@ -55,7 +55,7 @@ static void test_mem_protect(void)
|
|||
OK(uc_emu_start(qc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 1));
|
||||
OK(uc_mem_read(qc, 0x2000 + 4, &mem, 4));
|
||||
|
||||
TEST_CHECK(mem == 0xdeadbeef);
|
||||
TEST_CHECK(LEINT32(mem) == 0xdeadbeef);
|
||||
|
||||
OK(uc_close(qc));
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ static void test_splitting_mmio_unmap(void)
|
|||
// mov ebx, [0x4004] <-- mmio read
|
||||
char code[] = "\x8b\x0d\x04\x30\x00\x00\x8b\x1d\x04\x40\x00\x00";
|
||||
int r_ecx, r_ebx;
|
||||
int bytes = 0xdeadbeef;
|
||||
int bytes = LEINT32(0xdeadbeef);
|
||||
|
||||
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||
|
||||
|
@ -142,6 +142,9 @@ static void test_mem_protect_map_ptr(void)
|
|||
TEST_CHECK(val == mem);
|
||||
|
||||
OK(uc_close(uc));
|
||||
|
||||
free(data2);
|
||||
free(data1);
|
||||
}
|
||||
|
||||
static void test_map_at_the_end(void)
|
||||
|
@ -181,8 +184,15 @@ static void test_map_big_memory(void)
|
|||
|
||||
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
|
||||
uint64_t requested_size = 0xfffffffffffff000; // assume 4K page size
|
||||
#else
|
||||
long ps = sysconf(_SC_PAGESIZE);
|
||||
uint64_t requested_size = (uint64_t)(-ps);
|
||||
#endif
|
||||
|
||||
uc_assert_err(UC_ERR_NOMEM,
|
||||
uc_mem_map(uc, 0x0, 0xfffffffffffff000, UC_PROT_ALL));
|
||||
uc_mem_map(uc, 0x0, requested_size, UC_PROT_ALL));
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ static void test_mips_lwx_exception_issue_1314(void)
|
|||
reg = 0;
|
||||
OK(uc_reg_write(uc, UC_MIPS_REG_1, ®));
|
||||
OK(uc_reg_write(uc, UC_MIPS_REG_T9, ®));
|
||||
reg = 0xdeadbeef;
|
||||
reg = LEINT32(0xdeadbeef);
|
||||
OK(uc_mem_write(uc, 0x10000, ®, 4));
|
||||
reg = 0x10000;
|
||||
OK(uc_reg_write(uc, UC_MIPS_REG_S3, ®));
|
||||
|
|
|
@ -89,7 +89,24 @@ static void test_ppc32_sc(void)
|
|||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_ppc32_cr(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
uint32_t r_cr = 0x12345678;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_32 | UC_MODE_BIG_ENDIAN, NULL, 0);
|
||||
|
||||
OK(uc_reg_write(uc, UC_PPC_REG_CR, &r_cr));
|
||||
r_cr = 0;
|
||||
OK(uc_reg_read(uc, UC_PPC_REG_CR, &r_cr));
|
||||
|
||||
TEST_CHECK(r_cr == 0x12345678);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {{"test_ppc32_add", test_ppc32_add},
|
||||
{"test_ppc32_fadd", test_ppc32_fadd},
|
||||
{"test_ppc32_sc", test_ppc32_sc},
|
||||
{"test_ppc32_cr", test_ppc32_cr},
|
||||
{NULL, NULL}};
|
|
@ -422,7 +422,7 @@ static void test_x86_x87_fnstenv(void)
|
|||
|
||||
OK(uc_mem_read(uc, base, fnstenv, sizeof(fnstenv)));
|
||||
// But update FCS:FIP for fld.
|
||||
TEST_CHECK(fnstenv[3] == last_eip);
|
||||
TEST_CHECK(LEINT32(fnstenv[3]) == last_eip);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
@ -530,7 +530,7 @@ static void test_x86_smc_xor(void)
|
|||
|
||||
OK(uc_mem_read(uc, code_start + 3, (void *)&result, 4));
|
||||
|
||||
TEST_CHECK(result == (0x3ea98b13 ^ 0xbc4177e6));
|
||||
TEST_CHECK(LEINT32(result) == (0x3ea98b13 ^ 0xbc4177e6));
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
@ -562,7 +562,7 @@ static void test_x86_mmio_uc_mem_rw_write_callback(uc_engine *uc,
|
|||
static void test_x86_mmio_uc_mem_rw(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
int data = 0xdeadbeef;
|
||||
int data = LEINT32(0xdeadbeef);
|
||||
|
||||
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||
|
||||
|
@ -572,7 +572,7 @@ static void test_x86_mmio_uc_mem_rw(void)
|
|||
OK(uc_mem_write(uc, 0x20004, (void *)&data, 4));
|
||||
OK(uc_mem_read(uc, 0x20008, (void *)&data, 4));
|
||||
|
||||
TEST_CHECK(data == 0x19260817);
|
||||
TEST_CHECK(LEINT32(data) == 0x19260817);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
@ -1106,6 +1106,129 @@ static void test_x86_correct_address_in_long_jump_hook(void)
|
|||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_x86_invalid_vex_l(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
|
||||
/* vmovdqu ymm1, [rcx] */
|
||||
char code[] = {'\xC5', '\xFE', '\x6F', '\x09'};
|
||||
|
||||
/* initialize memory and run emulation */
|
||||
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||
OK(uc_mem_map(uc, 0, 2 * 1024 * 1024, UC_PROT_ALL));
|
||||
|
||||
OK(uc_mem_write(uc, 0, code, sizeof(code) / sizeof(code[0])));
|
||||
|
||||
uc_assert_err(UC_ERR_INSN_INVALID,
|
||||
uc_emu_start(uc, 0, sizeof(code) / sizeof(code[0]), 0, 0));
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
// AARCH64 inline the read while s390x won't split the access. Though not tested on other hosts
|
||||
// but we restrict a bit more.
|
||||
#if !defined(TARGET_READ_INLINED) && defined(BOOST_LITTLE_ENDIAN)
|
||||
|
||||
struct writelog_t {
|
||||
uint32_t addr, size;
|
||||
};
|
||||
|
||||
static void test_x86_unaligned_access_callback(uc_engine *uc, uc_mem_type type,
|
||||
uint64_t address, int size,
|
||||
int64_t value, void *user_data)
|
||||
{
|
||||
TEST_CHECK(size != 0);
|
||||
struct writelog_t *write_log = (struct writelog_t *)user_data;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (write_log[i].size == 0) {
|
||||
write_log[i].addr = (uint32_t)address;
|
||||
write_log[i].size = (uint32_t)size;
|
||||
return;
|
||||
}
|
||||
}
|
||||
TEST_ASSERT(false);
|
||||
}
|
||||
|
||||
static void test_x86_unaligned_access(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_hook hook;
|
||||
// mov dword ptr [0x200001], eax; mov eax, dword ptr [0x200001]
|
||||
char code[] = "\xa3\x01\x00\x20\x00\xa1\x01\x00\x20\x00";
|
||||
uint32_t r_eax = LEINT32(0x41424344);
|
||||
struct writelog_t write_log[10];
|
||||
struct writelog_t read_log[10];
|
||||
memset(write_log, 0, sizeof(write_log));
|
||||
memset(read_log, 0, sizeof(read_log));
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||
OK(uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_ALL));
|
||||
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_WRITE,
|
||||
test_x86_unaligned_access_callback, write_log, 1, 0));
|
||||
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_READ,
|
||||
test_x86_unaligned_access_callback, read_log, 1, 0));
|
||||
|
||||
OK(uc_reg_write(uc, UC_X86_REG_EAX, &r_eax));
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
TEST_CHECK(write_log[0].addr == 0x200001);
|
||||
TEST_CHECK(write_log[0].size == 4);
|
||||
TEST_CHECK(write_log[1].size == 0);
|
||||
|
||||
TEST_CHECK(read_log[0].addr == 0x200001);
|
||||
TEST_CHECK(read_log[0].size == 4);
|
||||
TEST_CHECK(read_log[1].size == 0);
|
||||
|
||||
char b;
|
||||
OK(uc_mem_read(uc, 0x200001, &b, 1));
|
||||
TEST_CHECK(b == 0x44);
|
||||
OK(uc_mem_read(uc, 0x200002, &b, 1));
|
||||
TEST_CHECK(b == 0x43);
|
||||
OK(uc_mem_read(uc, 0x200003, &b, 1));
|
||||
TEST_CHECK(b == 0x42);
|
||||
OK(uc_mem_read(uc, 0x200004, &b, 1));
|
||||
TEST_CHECK(b == 0x41);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool test_x86_lazy_mapping_mem_callback(uc_engine *uc, uc_mem_type type,
|
||||
uint64_t address, int size,
|
||||
int64_t value, void *user_data)
|
||||
{
|
||||
OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL));
|
||||
OK(uc_mem_write(uc, 0x1000, "\x90\x90", 2)); // nop; nop
|
||||
|
||||
// Handled!
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_x86_lazy_mapping_block_callback(uc_engine *uc,
|
||||
uint64_t address,
|
||||
uint32_t size, void *user_data)
|
||||
{
|
||||
int *block_count = (int *)user_data;
|
||||
(*block_count)++;
|
||||
}
|
||||
|
||||
static void test_x86_lazy_mapping(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_hook mem_hook, block_hook;
|
||||
int block_count = 0;
|
||||
|
||||
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||
OK(uc_hook_add(uc, &mem_hook, UC_HOOK_MEM_FETCH_UNMAPPED,
|
||||
test_x86_lazy_mapping_mem_callback, NULL, 1, 0));
|
||||
OK(uc_hook_add(uc, &block_hook, UC_HOOK_BLOCK,
|
||||
test_x86_lazy_mapping_block_callback, &block_count, 1, 0));
|
||||
|
||||
OK(uc_emu_start(uc, 0x1000, 0x1002, 0, 0));
|
||||
TEST_CHECK(block_count == 1);
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{"test_x86_in", test_x86_in},
|
||||
{"test_x86_out", test_x86_out},
|
||||
|
@ -1143,4 +1266,9 @@ TEST_LIST = {
|
|||
test_x86_correct_address_in_small_jump_hook},
|
||||
{"test_x86_correct_address_in_long_jump_hook",
|
||||
test_x86_correct_address_in_long_jump_hook},
|
||||
{"test_x86_invalid_vex_l", test_x86_invalid_vex_l},
|
||||
#if !defined(TARGET_READ_INLINED) && defined(BOOST_LITTLE_ENDIAN)
|
||||
{"test_x86_unaligned_access", test_x86_unaligned_access},
|
||||
#endif
|
||||
{"test_x86_lazy_mapping", test_x86_lazy_mapping},
|
||||
{NULL, NULL}};
|
||||
|
|
|
@ -5,6 +5,25 @@
|
|||
#include <stdint.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
#include "acutest.h"
|
||||
#include "endian.h"
|
||||
|
||||
// Copied from glibc-2.29
|
||||
|
||||
/* Swap bytes in 32 bit value. */
|
||||
#define bswap_32(x) \
|
||||
((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \
|
||||
(((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24))
|
||||
|
||||
/* Swap bytes in 64 bit value. */
|
||||
#define bswap_64(x) \
|
||||
((((x) & 0xff00000000000000ull) >> 56) \
|
||||
| (((x) & 0x00ff000000000000ull) >> 40) \
|
||||
| (((x) & 0x0000ff0000000000ull) >> 24) \
|
||||
| (((x) & 0x000000ff00000000ull) >> 8) \
|
||||
| (((x) & 0x00000000ff000000ull) << 8) \
|
||||
| (((x) & 0x0000000000ff0000ull) << 24) \
|
||||
| (((x) & 0x000000000000ff00ull) << 40) \
|
||||
| (((x) & 0x00000000000000ffull) << 56))
|
||||
|
||||
/**
|
||||
* Assert that err matches expect
|
||||
|
@ -22,4 +41,16 @@
|
|||
*/
|
||||
#define OK(stat) uc_assert_err(UC_ERR_OK, stat)
|
||||
|
||||
#ifdef BOOST_LITTLE_ENDIAN
|
||||
#define LEINT32(x) (x)
|
||||
#define LEINT64(x) (x)
|
||||
#define BEINT32(x) (bswap_32(x))
|
||||
#define BEINT64(x) (bswap_64(x))
|
||||
#else
|
||||
#define LEINT32(x) (bswap_32(x))
|
||||
#define LEINT64(x) (bswap_64(x))
|
||||
#define BEINT32(x) (x)
|
||||
#define BEINT64(x) (x)
|
||||
#endif
|
||||
|
||||
#endif /* UNICORN_TEST_H */
|
||||
|
|
57
uc.c
57
uc.c
|
@ -2,6 +2,7 @@
|
|||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
|
||||
|
||||
#include "unicorn/unicorn.h"
|
||||
#if defined(UNICORN_HAS_OSXKERNEL)
|
||||
#include <libkern/libkern.h>
|
||||
#else
|
||||
|
@ -753,12 +754,13 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
|||
}
|
||||
uc->nested_level++;
|
||||
|
||||
uint32_t begin_pc32 = READ_DWORD(begin);
|
||||
switch (uc->arch) {
|
||||
default:
|
||||
break;
|
||||
#ifdef UNICORN_HAS_M68K
|
||||
case UC_ARCH_M68K:
|
||||
uc_reg_write(uc, UC_M68K_REG_PC, &begin);
|
||||
uc_reg_write(uc, UC_M68K_REG_PC, &begin_pc32);
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_X86
|
||||
|
@ -767,7 +769,7 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
|||
default:
|
||||
break;
|
||||
case UC_MODE_16: {
|
||||
uint64_t ip;
|
||||
uint16_t ip;
|
||||
uint16_t cs;
|
||||
|
||||
uc_reg_read(uc, UC_X86_REG_CS, &cs);
|
||||
|
@ -777,7 +779,7 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
|||
break;
|
||||
}
|
||||
case UC_MODE_32:
|
||||
uc_reg_write(uc, UC_X86_REG_EIP, &begin);
|
||||
uc_reg_write(uc, UC_X86_REG_EIP, &begin_pc32);
|
||||
break;
|
||||
case UC_MODE_64:
|
||||
uc_reg_write(uc, UC_X86_REG_RIP, &begin);
|
||||
|
@ -787,7 +789,7 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
|||
#endif
|
||||
#ifdef UNICORN_HAS_ARM
|
||||
case UC_ARCH_ARM:
|
||||
uc_reg_write(uc, UC_ARM_REG_R15, &begin);
|
||||
uc_reg_write(uc, UC_ARM_REG_R15, &begin_pc32);
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_ARM64
|
||||
|
@ -798,7 +800,7 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
|||
#ifdef UNICORN_HAS_MIPS
|
||||
case UC_ARCH_MIPS:
|
||||
// TODO: MIPS32/MIPS64/BIGENDIAN etc
|
||||
uc_reg_write(uc, UC_MIPS_REG_PC, &begin);
|
||||
uc_reg_write(uc, UC_MIPS_REG_PC, &begin_pc32);
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_SPARC
|
||||
|
@ -809,12 +811,20 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
|||
#endif
|
||||
#ifdef UNICORN_HAS_PPC
|
||||
case UC_ARCH_PPC:
|
||||
uc_reg_write(uc, UC_PPC_REG_PC, &begin);
|
||||
if (uc->mode & UC_MODE_PPC64) {
|
||||
uc_reg_write(uc, UC_PPC_REG_PC, &begin);
|
||||
} else {
|
||||
uc_reg_write(uc, UC_PPC_REG_PC, &begin_pc32);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_RISCV
|
||||
case UC_ARCH_RISCV:
|
||||
uc_reg_write(uc, UC_RISCV_REG_PC, &begin);
|
||||
if (uc->mode & UC_MODE_RISCV64) {
|
||||
uc_reg_write(uc, UC_RISCV_REG_PC, &begin);
|
||||
} else {
|
||||
uc_reg_write(uc, UC_RISCV_REG_PC, &begin_pc32);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_S390X
|
||||
|
@ -824,7 +834,7 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
|||
#endif
|
||||
#ifdef UNICORN_HAS_TRICORE
|
||||
case UC_ARCH_TRICORE:
|
||||
uc_reg_write(uc, UC_TRICORE_REG_PC, &begin);
|
||||
uc_reg_write(uc, UC_TRICORE_REG_PC, &begin_pc32);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
@ -1861,7 +1871,7 @@ uc_err uc_context_alloc(uc_engine *uc, uc_context **context)
|
|||
|
||||
*_context = g_malloc(size);
|
||||
if (*_context) {
|
||||
(*_context)->context_size = uc->cpu_context_size;
|
||||
(*_context)->context_size = size - sizeof(uc_context);
|
||||
(*_context)->arch = uc->arch;
|
||||
(*_context)->mode = uc->mode;
|
||||
return UC_ERR_OK;
|
||||
|
@ -1881,8 +1891,13 @@ UNICORN_EXPORT
|
|||
size_t uc_context_size(uc_engine *uc)
|
||||
{
|
||||
UC_INIT(uc);
|
||||
// return the total size of struct uc_context
|
||||
return sizeof(uc_context) + uc->cpu_context_size;
|
||||
|
||||
if (!uc->context_size) {
|
||||
// return the total size of struct uc_context
|
||||
return sizeof(uc_context) + uc->cpu_context_size;
|
||||
} else {
|
||||
return sizeof(uc_context) + uc->context_size(uc);
|
||||
}
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
|
@ -1890,9 +1905,12 @@ uc_err uc_context_save(uc_engine *uc, uc_context *context)
|
|||
{
|
||||
UC_INIT(uc);
|
||||
|
||||
memcpy(context->data, uc->cpu->env_ptr, context->context_size);
|
||||
|
||||
return UC_ERR_OK;
|
||||
if (!uc->context_save) {
|
||||
memcpy(context->data, uc->cpu->env_ptr, context->context_size);
|
||||
return UC_ERR_OK;
|
||||
} else {
|
||||
return uc->context_save(uc, context);
|
||||
}
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
|
@ -2064,9 +2082,12 @@ uc_err uc_context_restore(uc_engine *uc, uc_context *context)
|
|||
{
|
||||
UC_INIT(uc);
|
||||
|
||||
memcpy(uc->cpu->env_ptr, context->data, context->context_size);
|
||||
|
||||
return UC_ERR_OK;
|
||||
if (!uc->context_restore) {
|
||||
memcpy(uc->cpu->env_ptr, context->data, context->context_size);
|
||||
return UC_ERR_OK;
|
||||
} else {
|
||||
return uc->context_restore(uc, context);
|
||||
}
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
|
@ -2240,7 +2261,7 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
|
|||
} else {
|
||||
int model = va_arg(args, int);
|
||||
|
||||
if (model <= 0 || uc->init_done) {
|
||||
if (model < 0 || uc->init_done) {
|
||||
err = UC_ERR_ARG;
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue