Merge branch 'dev'

This commit is contained in:
Nguyen Anh Quynh 2022-11-01 13:56:59 +08:00
commit 3c53a64e30
71 changed files with 1351 additions and 669 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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'

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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
()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
</configuration>

View File

@ -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();

View File

@ -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")]

View File

@ -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;
}

View File

@ -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>

View File

@ -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();
}

View File

@ -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;
}

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Gee.External.Capstone" version="1.2.2" targetFramework="net45" />
</packages>

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

3
bindings/python/sample_ctl.py Normal file → Executable file
View File

@ -1,4 +1,5 @@
# Unicorn Emulator Engine
#!/usr/bin/env python
# Sample code for Unicorn.
# By Lazymio(@wtdcode), 2021
from unicorn import *

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
# Sample code for S390x of Unicorn.
from unicorn import *
from unicorn.s390x_const import *

View File

@ -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")))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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`

View File

@ -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;

View File

@ -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

View File

@ -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.

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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".

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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"

View File

@ -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;
}

75
tests/unit/endian.h Normal file
View File

@ -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

View File

@ -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}};

View File

@ -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}};

View File

@ -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}};

View File

@ -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));
}

View File

@ -112,7 +112,7 @@ static void test_mips_lwx_exception_issue_1314(void)
reg = 0;
OK(uc_reg_write(uc, UC_MIPS_REG_1, &reg));
OK(uc_reg_write(uc, UC_MIPS_REG_T9, &reg));
reg = 0xdeadbeef;
reg = LEINT32(0xdeadbeef);
OK(uc_mem_write(uc, 0x10000, &reg, 4));
reg = 0x10000;
OK(uc_reg_write(uc, UC_MIPS_REG_S3, &reg));

View File

@ -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}};

View File

@ -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}};

View File

@ -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
View File

@ -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;
}