Merge branch 'dev' into zig-bindgen
This commit is contained in:
@@ -90,10 +90,10 @@ template = {
|
||||
'comment_close': '',
|
||||
},
|
||||
'dotnet': {
|
||||
'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\nnamespace UnicornManaged.Const\n\nopen System\n\n[<AutoOpen>]\nmodule %s =\n",
|
||||
'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\nnamespace UnicornEngine.Const\n\nopen System\n\n[<AutoOpen>]\nmodule %s =\n",
|
||||
'footer': "\n",
|
||||
'line_format': ' let UC_%s = %s\n',
|
||||
'out_file': os.path.join('dotnet', 'UnicornManaged', 'Const', '%s.fs'),
|
||||
'out_file': os.path.join('dotnet', 'UnicornEngine', 'Const', '%s.fs'),
|
||||
# prefixes for constant filenames of all archs - case sensitive
|
||||
'arm.h': 'Arm',
|
||||
'arm64.h': 'Arm64',
|
||||
|
||||
@@ -5,7 +5,7 @@ VisualStudioVersion = 14.0.23107.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicornSamples", "UnicornSamples\UnicornSamples.csproj", "{B80B5987-1E24-4309-8BF9-C4F91270F21C}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UnicornManaged", "UnicornManaged\UnicornManaged.fsproj", "{0C21F1C1-2725-4A46-9022-1905F85822A5}"
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UnicornEngine", "UnicornEngine\UnicornEngine.fsproj", "{0C21F1C1-2725-4A46-9022-1905F85822A5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UnicornManaged.Binding
|
||||
namespace UnicornEngine.Binding
|
||||
|
||||
|
||||
module BindingFactory =
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UnicornManaged.Binding
|
||||
namespace UnicornEngine.Binding
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UnicornManaged.Binding
|
||||
namespace UnicornEngine.Binding
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UnicornManaged.Binding
|
||||
namespace UnicornEngine.Binding
|
||||
|
||||
open System
|
||||
open System.Runtime.InteropServices
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -9,13 +9,13 @@ module Common =
|
||||
let UC_API_MAJOR = 2
|
||||
|
||||
let UC_API_MINOR = 0
|
||||
let UC_API_PATCH = 1
|
||||
let UC_API_EXTRA = 255
|
||||
let UC_API_PATCH = 2
|
||||
let UC_API_EXTRA = 1
|
||||
let UC_VERSION_MAJOR = 2
|
||||
|
||||
let UC_VERSION_MINOR = 0
|
||||
let UC_VERSION_PATCH = 1
|
||||
let UC_VERSION_EXTRA = 255
|
||||
let UC_VERSION_PATCH = 2
|
||||
let UC_VERSION_EXTRA = 1
|
||||
let UC_SECOND_SCALE = 1000000
|
||||
let UC_MILISECOND_SCALE = 1000
|
||||
let UC_ARCH_ARM = 1
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
namespace UnicornManaged.Const
|
||||
namespace UnicornEngine.Const
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UnicornManaged
|
||||
namespace UnicornEngine
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UnicornManaged
|
||||
namespace UnicornEngine
|
||||
|
||||
open System
|
||||
open System.Runtime.InteropServices
|
||||
@@ -14,10 +14,10 @@ type internal BlockHookInternal = delegate of IntPtr * Int64 * Int32 * IntPtr ->
|
||||
type internal InterruptHookInternal = delegate of IntPtr * Int32 * IntPtr -> unit
|
||||
|
||||
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
|
||||
type internal MemReadHookInternal = delegate of IntPtr * Int64 * Int32 * IntPtr -> unit
|
||||
type internal MemReadHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * IntPtr -> unit
|
||||
|
||||
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
|
||||
type internal MemWriteHookInternal = delegate of IntPtr * Int64 * Int32 * Int64 * IntPtr -> unit
|
||||
type internal MemWriteHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * Int64 * IntPtr -> unit
|
||||
|
||||
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
|
||||
type internal EventMemHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * Int64 * IntPtr-> Boolean
|
||||
356
bindings/dotnet/UnicornEngine/Unicorn.fs
Normal file
356
bindings/dotnet/UnicornEngine/Unicorn.fs
Normal file
@@ -0,0 +1,356 @@
|
||||
namespace UnicornEngine
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Runtime.InteropServices
|
||||
open System.Linq
|
||||
open UnicornEngine.Const
|
||||
open UnicornEngine.Binding
|
||||
|
||||
// exported hooks
|
||||
type CodeHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
|
||||
and BlockHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
|
||||
and InterruptHook = delegate of Unicorn * Int32 * Object -> unit
|
||||
and MemReadHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
|
||||
and MemWriteHook = delegate of Unicorn * Int64 * Int32 * Int64 * Object -> unit
|
||||
and EventMemHook = delegate of Unicorn * Int32 * Int64 * Int32 * Int64 * Object -> Boolean
|
||||
and InHook = delegate of Unicorn * Int32 * Int32 * Object -> Int32
|
||||
and OutHook = delegate of Unicorn * Int32 * Int32 * Int32 * Object -> unit
|
||||
and SyscallHook = delegate of Unicorn * Object -> unit
|
||||
|
||||
// the managed unicorn engine
|
||||
and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
||||
|
||||
// hook callback list
|
||||
let _codeHooks = new List<(CodeHook * (UIntPtr * Object * Object))>()
|
||||
let _blockHooks = new List<(BlockHook * (UIntPtr * Object * Object))>()
|
||||
let _interruptHooks = new List<(InterruptHook * (UIntPtr * Object * Object))>()
|
||||
let _memReadHooks = new List<(MemReadHook * (UIntPtr * Object * Object))>()
|
||||
let _memWriteHooks = new List<(MemWriteHook * (UIntPtr * Object * Object))>()
|
||||
let _memEventHooks = new Dictionary<Int32, List<(EventMemHook * (UIntPtr * Object * Object))>>()
|
||||
let _inHooks = new List<(InHook * (UIntPtr * Object * Object))>()
|
||||
let _outHooks = new List<(OutHook * (UIntPtr * Object * Object))>()
|
||||
let _syscallHooks = new List<(SyscallHook * (UIntPtr * Object * Object))>()
|
||||
let _disposablePointers = new List<nativeint>()
|
||||
|
||||
let _eventMemMap =
|
||||
[
|
||||
(UC_HOOK_MEM_READ_UNMAPPED, UC_MEM_READ_UNMAPPED)
|
||||
(UC_HOOK_MEM_WRITE_UNMAPPED, UC_MEM_WRITE_UNMAPPED)
|
||||
(UC_HOOK_MEM_FETCH_UNMAPPED, UC_MEM_FETCH_UNMAPPED)
|
||||
(UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT)
|
||||
(UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT)
|
||||
(UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT)
|
||||
] |> dict
|
||||
|
||||
let mutable _eng = [|UIntPtr.Zero|]
|
||||
|
||||
let strError(errorNo: Int32) =
|
||||
let errorStringPointer = binding.Strerror(errorNo)
|
||||
Marshal.PtrToStringAnsi(errorStringPointer)
|
||||
|
||||
let checkResult(errorCode: Int32) =
|
||||
// return the exception instead of raising it in order to have a more meaningful stack trace
|
||||
if errorCode <> Common.UC_ERR_OK then
|
||||
let errorMessage = strError(errorCode)
|
||||
Some <| UnicornEngineException(errorCode, errorMessage)
|
||||
else None
|
||||
|
||||
let hookDel(callbacks: List<'a * (UIntPtr * Object * Object)>) (callback: 'a)=
|
||||
match callbacks |> Seq.tryFind(fun item -> match item with | (c, _) -> c = callback) with
|
||||
| Some(item) ->
|
||||
let (hh, _, _) = snd item
|
||||
match binding.HookDel(_eng.[0], hh) |> checkResult with
|
||||
| Some e -> raise e
|
||||
| None -> callbacks.Remove(item) |> ignore
|
||||
| None -> ()
|
||||
|
||||
let allocate(size: Int32) =
|
||||
let mem = Marshal.AllocHGlobal(size)
|
||||
_disposablePointers.Add(mem)
|
||||
mem.ToPointer()
|
||||
|
||||
do
|
||||
// initialize event list
|
||||
_eventMemMap
|
||||
|> Seq.map(fun kv -> kv.Key)
|
||||
|> Seq.iter (fun eventType -> _memEventHooks.Add(eventType, new List<EventMemHook * (UIntPtr * Object * Object)>()))
|
||||
|
||||
// init engine
|
||||
_eng <- [|new UIntPtr(allocate(IntPtr.Size))|]
|
||||
let err = binding.UcOpen(uint32 arch, uint32 mode, _eng)
|
||||
if err <> Common.UC_ERR_OK then
|
||||
raise(ApplicationException(String.Format("Unable to open the Unicorn Engine. Error: {0}", err)))
|
||||
|
||||
new(arch, mode) = new Unicorn(arch, mode, BindingFactory.getDefault())
|
||||
|
||||
member this.MemMap(address: Int64, size: Int64, perm: Int32) =
|
||||
let size = new UIntPtr(uint64 size)
|
||||
match binding.MemMap(_eng.[0], uint64 address, size, uint32 perm) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemMapPtr(address: Int64, size: Int64, perm: Int32, ptr: IntPtr) =
|
||||
let size = new UIntPtr(uint64 size)
|
||||
let ptr = new UIntPtr(ptr.ToPointer())
|
||||
match binding.MemMapPtr(_eng.[0], uint64 address, size, uint32 perm, ptr) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemUnmap(address: Int64, size: Int64) =
|
||||
let size = new UIntPtr(uint64 size)
|
||||
match binding.MemUnmap(_eng.[0], uint64 address, size) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemProtect(address: Int64, size: Int64, ?perm: Int32) =
|
||||
let size = new UIntPtr(uint64 size)
|
||||
let perm = defaultArg perm Common.UC_PROT_ALL
|
||||
match binding.MemProtect(_eng.[0], uint64 address, size, uint32 perm) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemWrite(address: Int64, value: Byte array) =
|
||||
match binding.MemWrite(_eng.[0], uint64 address, value, new UIntPtr(uint32 value.Length)) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemRead(address: Int64, memValue: Byte array) =
|
||||
match binding.MemRead(_eng.[0], uint64 address, memValue, new UIntPtr(uint32 memValue.Length)) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.RegWrite(regId: Int32, value: Byte array) =
|
||||
match binding.RegWrite(_eng.[0], regId, value) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.RegWrite(regId: Int32, value: Int64) =
|
||||
this.RegWrite(regId, int64ToBytes value)
|
||||
|
||||
member this.RegRead(regId: Int32, regValue: Byte array) =
|
||||
match binding.RegRead(_eng.[0], regId, regValue) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.RegRead(regId: Int32) =
|
||||
let buffer = Array.zeroCreate<Byte> 8
|
||||
this.RegRead(regId, buffer)
|
||||
bytesToInt64 buffer
|
||||
|
||||
member this.EmuStart(beginAddr: Int64, untilAddr: Int64, timeout: Int64, count: Int64) =
|
||||
match binding.EmuStart(_eng.[0], uint64 beginAddr, uint64 untilAddr, uint64 timeout, uint64 count) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.EmuStop() =
|
||||
match binding.EmuStop(_eng.[0]) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.Close() =
|
||||
match binding.Close(_eng.[0]) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.ArchSupported(arch: Int32) =
|
||||
binding.ArchSupported(arch)
|
||||
|
||||
member this.ErrNo() =
|
||||
binding.Errono(_eng.[0])
|
||||
|
||||
member this.AddCodeHook(callback: CodeHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) =
|
||||
callback.Invoke(this, addr, size, userData)
|
||||
|
||||
let codeHookInternal = new CodeHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(codeHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_CODE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_codeHooks.Add(callback, (hh, userData, codeHookInternal))
|
||||
|
||||
member this.AddCodeHook(callback: CodeHook, beginAddr: Int64, endAddr: Int64) =
|
||||
this.AddCodeHook(callback, null, beginAddr, endAddr)
|
||||
|
||||
member this.HookDel(callback: CodeHook) =
|
||||
hookDel _codeHooks callback
|
||||
|
||||
member this.AddBlockHook(callback: BlockHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) =
|
||||
callback.Invoke(this, addr, size, userData)
|
||||
|
||||
let blockHookInternal = new BlockHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(blockHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_BLOCK, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_blockHooks.Add(callback, (hh, userData, blockHookInternal))
|
||||
|
||||
member this.HookDel(callback: BlockHook) =
|
||||
hookDel _blockHooks callback
|
||||
|
||||
member this.AddInterruptHook(callback: InterruptHook, userData: Object, hookBegin: UInt64, hookEnd : UInt64) =
|
||||
let trampoline(u: IntPtr) (intNumber: Int32) (user: IntPtr) =
|
||||
callback.Invoke(this, intNumber, userData)
|
||||
|
||||
let interruptHookInternal = new InterruptHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(interruptHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_INTR, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, hookBegin, hookEnd) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_interruptHooks.Add(callback, (hh, userData, interruptHookInternal))
|
||||
|
||||
member this.AddInterruptHook(callback: InterruptHook) =
|
||||
this.AddInterruptHook(callback, null, uint64 1, uint64 0)
|
||||
|
||||
member this.HookDel(callback: InterruptHook) =
|
||||
hookDel _interruptHooks callback
|
||||
|
||||
member this.AddMemReadHook(callback: MemReadHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (_eventType: Int32) (addr: Int64) (size: Int32) (user: IntPtr) =
|
||||
callback.Invoke(this, addr, size, userData)
|
||||
|
||||
let memReadHookInternal = new MemReadHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(memReadHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_READ, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_memReadHooks.Add(callback, (hh, userData, memReadHookInternal))
|
||||
|
||||
member this.HookDel(callback: MemReadHook) =
|
||||
hookDel _memReadHooks callback
|
||||
|
||||
member this.AddMemWriteHook(callback: MemWriteHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (_eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) =
|
||||
callback.Invoke(this, addr, size, value, userData)
|
||||
|
||||
let memWriteHookInternal = new MemWriteHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(memWriteHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_WRITE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_memWriteHooks.Add(callback, (hh, userData, memWriteHookInternal))
|
||||
|
||||
member this.HookDel(callback: MemWriteHook) =
|
||||
hookDel _memWriteHooks callback
|
||||
|
||||
member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) =
|
||||
callback.Invoke(this, eventType, addr, size, value, userData)
|
||||
|
||||
// register the event if not already done
|
||||
_memEventHooks.Keys
|
||||
|> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0)
|
||||
|> Seq.iter(fun eventFlag ->
|
||||
let memEventHookInternal = new EventMemHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(memEventHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, eventFlag, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_memEventHooks.[eventFlag].Add((callback, (hh, userData, memEventHookInternal)))
|
||||
)
|
||||
|
||||
member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object) =
|
||||
this.AddEventMemHook(callback, eventType, userData, 1, 0)
|
||||
|
||||
member this.AddEventMemHook(callback: EventMemHook, eventType: Int32) =
|
||||
this.AddEventMemHook(callback, eventType, null)
|
||||
|
||||
member this.HookDel(callback: EventMemHook) =
|
||||
_memEventHooks.Keys
|
||||
|> Seq.iter(fun eventFlag -> hookDel _memEventHooks.[eventFlag] callback)
|
||||
|
||||
member this.AddInHook(callback: InHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (port: Int32) (size: Int32) (user: IntPtr) =
|
||||
callback.Invoke(this, port, size, userData)
|
||||
|
||||
let inHookInternal = new InHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(inHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_IN) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_inHooks.Add(callback, (hh, userData, inHookInternal))
|
||||
|
||||
member this.AddInHook(callback: InHook, userData: Object) =
|
||||
this.AddInHook(callback, userData, 1, 0)
|
||||
|
||||
member this.AddInHook(callback: InHook) =
|
||||
this.AddInHook(callback, null)
|
||||
|
||||
member this.HookDel(callback: InHook) =
|
||||
hookDel _inHooks callback
|
||||
|
||||
member this.AddOutHook(callback: OutHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (port: Int32) (size: Int32) (value: Int32) (user: IntPtr) =
|
||||
callback.Invoke(this, port, size, value, userData)
|
||||
|
||||
let outHookInternal = new OutHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(outHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_OUT) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_outHooks.Add(callback, (hh, userData, outHookInternal))
|
||||
|
||||
member this.AddOutHook(callback: OutHook, userData: Object) =
|
||||
this.AddOutHook(callback, userData, 1, 0)
|
||||
|
||||
member this.AddOutHook(callback: OutHook) =
|
||||
this.AddOutHook(callback, null)
|
||||
|
||||
member this.HookDel(callback: OutHook) =
|
||||
hookDel _outHooks callback
|
||||
|
||||
member this.AddSyscallHook(callback: SyscallHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (user: IntPtr) =
|
||||
callback.Invoke(this, userData)
|
||||
|
||||
let syscallHookInternal = new SyscallHookInternal(trampoline)
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(syscallHookInternal)
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_SYSCALL) |> checkResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
|
||||
_syscallHooks.Add(callback, (hh, userData, syscallHookInternal))
|
||||
|
||||
member this.AddSyscallHook(callback: SyscallHook, userData: Object) =
|
||||
this.AddSyscallHook(callback, userData, 1, 0)
|
||||
|
||||
member this.AddSyscallHook(callback: SyscallHook) =
|
||||
this.AddSyscallHook(callback, null)
|
||||
|
||||
member this.HookDel(callback: SyscallHook) =
|
||||
hookDel _syscallHooks callback
|
||||
|
||||
member this.Version() =
|
||||
let (major, minor) = (new UIntPtr(), new UIntPtr())
|
||||
let combined = binding.Version(major, minor)
|
||||
(major.ToUInt32(), minor.ToUInt32(), combined)
|
||||
|
||||
abstract Dispose : Boolean -> unit
|
||||
default this.Dispose(disposing: Boolean) =
|
||||
if (disposing) then
|
||||
// free managed resources, this is the default dispose implementation pattern
|
||||
()
|
||||
|
||||
_disposablePointers
|
||||
|> Seq.filter(fun pointer -> pointer <> IntPtr.Zero)
|
||||
|> Seq.iter Marshal.FreeHGlobal
|
||||
_disposablePointers.Clear()
|
||||
|
||||
member this.Dispose() =
|
||||
this.Dispose(true)
|
||||
GC.SuppressFinalize(this)
|
||||
|
||||
override this.Finalize() =
|
||||
this.Dispose(false)
|
||||
|
||||
interface IDisposable with
|
||||
member this.Dispose() =
|
||||
this.Dispose()
|
||||
@@ -1,11 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>UnicornManaged</RootNamespace>
|
||||
<AssemblyName>UnicornManaged</AssemblyName>
|
||||
<PackageId>UnicornEngine.Unicorn</PackageId>
|
||||
<Authors>UnicornEngine</Authors>
|
||||
<Copyright>Copyright © Antonio Parata 2016</Copyright>
|
||||
<RepositoryUrl>https://github.com/unicorn-engine/unicorn</RepositoryUrl>
|
||||
<Version>2.0.0</Version>
|
||||
<PackageDescription>.NET bindings for unicorn</PackageDescription>
|
||||
<VersionPrefix>2.0.2-rc1</VersionPrefix>
|
||||
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
||||
<ProjectGuid>0c21f1c1-2725-4a46-9022-1905f85822a5</ProjectGuid>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
@@ -15,6 +17,10 @@
|
||||
<WarningLevel>3</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugType>none</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Const\Arm.fs" />
|
||||
<Compile Include="Const\Arm64.fs" />
|
||||
@@ -36,4 +42,8 @@
|
||||
<Compile Include="ConvertUtility.fs" />
|
||||
<Compile Include="Unicorn.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\**" PackagePath="runtimes" Visible="false" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UnicornManaged
|
||||
namespace UnicornEngine
|
||||
|
||||
open System
|
||||
|
||||
@@ -1,342 +0,0 @@
|
||||
namespace UnicornManaged
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Runtime.InteropServices
|
||||
open System.Linq
|
||||
open UnicornManaged.Const
|
||||
open UnicornManaged.Binding
|
||||
|
||||
// exported hooks
|
||||
type CodeHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
|
||||
and BlockHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
|
||||
and InterruptHook = delegate of Unicorn * Int32 * Object -> unit
|
||||
and MemReadHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
|
||||
and MemWriteHook = delegate of Unicorn * Int64 * Int32 * Int64 * Object -> unit
|
||||
and EventMemHook = delegate of Unicorn * Int32 * Int64 * Int32 * Int64 * Object -> Boolean
|
||||
and InHook = delegate of Unicorn * Int32 * Int32 * Object -> Int32
|
||||
and OutHook = delegate of Unicorn * Int32 * Int32 * Int32 * Object -> unit
|
||||
and SyscallHook = delegate of Unicorn * Object -> unit
|
||||
|
||||
// the managed unicorn engine
|
||||
and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
|
||||
|
||||
// hook callback list
|
||||
let _codeHooks = new List<(CodeHook * Object)>()
|
||||
let _blockHooks = new List<(BlockHook * Object)>()
|
||||
let _interruptHooks = new List<(InterruptHook * Object)>()
|
||||
let _memReadHooks = new List<(MemReadHook * Object)>()
|
||||
let _memWriteHooks = new List<(MemWriteHook * Object)>()
|
||||
let _memEventHooks = new Dictionary<Int32, List<(EventMemHook * Object)>>()
|
||||
let _inHooks = new List<(InHook * Object)>()
|
||||
let _outHooks = new List<(OutHook * Object)>()
|
||||
let _syscallHooks = new List<(SyscallHook * Object)>()
|
||||
let _disposablePointers = new List<nativeint>()
|
||||
|
||||
let _eventMemMap =
|
||||
[
|
||||
(UC_HOOK_MEM_READ_UNMAPPED, UC_MEM_READ_UNMAPPED)
|
||||
(UC_HOOK_MEM_WRITE_UNMAPPED, UC_MEM_WRITE_UNMAPPED)
|
||||
(UC_HOOK_MEM_FETCH_UNMAPPED, UC_MEM_FETCH_UNMAPPED)
|
||||
(UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT)
|
||||
(UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT)
|
||||
(UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT)
|
||||
] |> dict
|
||||
|
||||
let mutable _eng = [|UIntPtr.Zero|]
|
||||
|
||||
let checkResult(errCode: Int32, errMsg: String) =
|
||||
if errCode <> Common.UC_ERR_OK then raise(ApplicationException(String.Format("{0}. Error: {1}", errMsg, errCode)))
|
||||
|
||||
let hookDel(callbacks: List<'a * Object>) (callback: 'a)=
|
||||
// TODO: invoke the native function in order to not call the trampoline anymore
|
||||
callbacks
|
||||
|> Seq.tryFind(fun item -> match item with | (c, _) -> c = callback)
|
||||
|> (fun k -> if k.IsSome then callbacks.Remove(k.Value) |> ignore)
|
||||
|
||||
let allocate(size: Int32) =
|
||||
let mem = Marshal.AllocHGlobal(size)
|
||||
_disposablePointers.Add(mem)
|
||||
mem.ToPointer()
|
||||
|
||||
do
|
||||
// initialize event list
|
||||
_eventMemMap
|
||||
|> Seq.map(fun kv -> kv.Key)
|
||||
|> Seq.iter (fun eventType -> _memEventHooks.Add(eventType, new List<EventMemHook * Object>()))
|
||||
|
||||
// init engine
|
||||
_eng <- [|new UIntPtr(allocate(IntPtr.Size))|]
|
||||
let err = binding.UcOpen(uint32 arch, uint32 mode, _eng)
|
||||
checkResult(err, "Unable to open the Unicorn Engine")
|
||||
|
||||
new(arch, mode) = new Unicorn(arch, mode, BindingFactory.getDefault())
|
||||
|
||||
member private this.CheckResult(errorCode: Int32) =
|
||||
// return the exception instead of raising it in order to have a more meaningful stack trace
|
||||
if errorCode <> Common.UC_ERR_OK then
|
||||
let errorMessage = this.StrError(errorCode)
|
||||
Some <| UnicornEngineException(errorCode, errorMessage)
|
||||
else None
|
||||
|
||||
member this.MemMap(address: Int64, size: Int64, perm: Int32) =
|
||||
let size = new UIntPtr(uint64 size)
|
||||
match binding.MemMap(_eng.[0], uint64 address, size, uint32 perm) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemMapPtr(address: Int64, size: Int64, perm: Int32, ptr: IntPtr) =
|
||||
let size = new UIntPtr(uint64 size)
|
||||
let ptr = new UIntPtr(ptr.ToPointer())
|
||||
match binding.MemMapPtr(_eng.[0], uint64 address, size, uint32 perm, ptr) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemUnmap(address: Int64, size: Int64) =
|
||||
let size = new UIntPtr(uint64 size)
|
||||
match binding.MemUnmap(_eng.[0], uint64 address, size) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemProtect(address: Int64, size: Int64, ?perm: Int32) =
|
||||
let size = new UIntPtr(uint64 size)
|
||||
let perm = defaultArg perm Common.UC_PROT_ALL
|
||||
match binding.MemProtect(_eng.[0], uint64 address, size, uint32 perm) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemWrite(address: Int64, value: Byte array) =
|
||||
match binding.MemWrite(_eng.[0], uint64 address, value, new UIntPtr(uint32 value.Length)) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.MemRead(address: Int64, memValue: Byte array) =
|
||||
match binding.MemRead(_eng.[0], uint64 address, memValue, new UIntPtr(uint32 memValue.Length)) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.RegWrite(regId: Int32, value: Byte array) =
|
||||
match binding.RegWrite(_eng.[0], regId, value) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.RegWrite(regId: Int32, value: Int64) =
|
||||
this.RegWrite(regId, int64ToBytes value)
|
||||
|
||||
member this.RegRead(regId: Int32, regValue: Byte array) =
|
||||
match binding.RegRead(_eng.[0], regId, regValue) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.RegRead(regId: Int32) =
|
||||
let buffer = Array.zeroCreate<Byte> 8
|
||||
this.RegRead(regId, buffer)
|
||||
bytesToInt64 buffer
|
||||
|
||||
member this.EmuStart(beginAddr: Int64, untilAddr: Int64, timeout: Int64, count: Int64) =
|
||||
match binding.EmuStart(_eng.[0], uint64 beginAddr, uint64 untilAddr, uint64 timeout, uint64 count) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.EmuStop() =
|
||||
match binding.EmuStop(_eng.[0]) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.Close() =
|
||||
match binding.Close(_eng.[0]) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
member this.ArchSupported(arch: Int32) =
|
||||
binding.ArchSupported(arch)
|
||||
|
||||
member this.ErrNo() =
|
||||
binding.Errono(_eng.[0])
|
||||
|
||||
member this.StrError(errorNo: Int32) =
|
||||
let errorStringPointer = binding.Strerror(errorNo)
|
||||
Marshal.PtrToStringAnsi(errorStringPointer)
|
||||
|
||||
member this.AddCodeHook(callback: CodeHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) =
|
||||
_codeHooks
|
||||
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData))
|
||||
|
||||
if _codeHooks |> Seq.isEmpty then
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new CodeHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_CODE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
_codeHooks.Add(callback, userData)
|
||||
|
||||
member this.AddCodeHook(callback: CodeHook, beginAddr: Int64, endAddr: Int64) =
|
||||
this.AddCodeHook(callback, null, beginAddr, endAddr)
|
||||
|
||||
member this.HookDel(callback: CodeHook) =
|
||||
hookDel _codeHooks callback
|
||||
|
||||
member this.AddBlockHook(callback: BlockHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) =
|
||||
_blockHooks
|
||||
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData))
|
||||
|
||||
if _blockHooks |> Seq.isEmpty then
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new BlockHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_BLOCK, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
_blockHooks.Add(callback, userData)
|
||||
|
||||
member this.HookDel(callback: BlockHook) =
|
||||
hookDel _blockHooks callback
|
||||
|
||||
member this.AddInterruptHook(callback: InterruptHook, userData: Object, hookBegin: UInt64, hookEnd : UInt64) =
|
||||
let trampoline(u: IntPtr) (intNumber: Int32) (user: IntPtr) =
|
||||
_interruptHooks
|
||||
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, intNumber, userData))
|
||||
|
||||
if _interruptHooks |> Seq.isEmpty then
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new InterruptHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_INTR, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, hookBegin, hookEnd) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
_interruptHooks.Add(callback, userData)
|
||||
|
||||
member this.AddInterruptHook(callback: InterruptHook) =
|
||||
this.AddInterruptHook(callback, null, uint64 1, uint64 0)
|
||||
|
||||
member this.HookDel(callback: InterruptHook) =
|
||||
hookDel _interruptHooks callback
|
||||
|
||||
member this.AddMemReadHook(callback: MemReadHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) =
|
||||
_memReadHooks
|
||||
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData))
|
||||
|
||||
if _memReadHooks |> Seq.isEmpty then
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemReadHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_READ, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
_memReadHooks.Add(callback, userData)
|
||||
|
||||
member this.HookDel(callback: MemReadHook) =
|
||||
hookDel _memReadHooks callback
|
||||
|
||||
member this.AddMemWriteHook(callback: MemWriteHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
|
||||
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) =
|
||||
_memWriteHooks
|
||||
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, value, userData))
|
||||
|
||||
if _memWriteHooks |> Seq.isEmpty then
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemWriteHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_WRITE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
_memWriteHooks.Add(callback, userData)
|
||||
|
||||
member this.HookDel(callback: MemWriteHook) =
|
||||
hookDel _memWriteHooks callback
|
||||
|
||||
member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object) =
|
||||
let trampoline(u: IntPtr) (eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) =
|
||||
_memEventHooks.Keys
|
||||
|> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0)
|
||||
|> Seq.map(fun eventflag -> _memEventHooks.[eventflag])
|
||||
|> Seq.concat
|
||||
|> Seq.map(fun (callback, userData) -> callback.Invoke(this, eventType, addr, size, value, userData))
|
||||
|> Seq.forall id
|
||||
|
||||
// register the event if not already done
|
||||
_memEventHooks.Keys
|
||||
|> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0)
|
||||
|> Seq.filter(fun eventFlag -> _memEventHooks.[eventFlag] |> Seq.isEmpty)
|
||||
|> Seq.iter(fun eventFlag ->
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new EventMemHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddNoarg(_eng.[0], hh, eventFlag, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
)
|
||||
|
||||
// register the callbacks
|
||||
_memEventHooks.Keys
|
||||
|> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0)
|
||||
|> Seq.iter(fun eventFlag -> _memEventHooks.[eventFlag].Add((callback, userData)))
|
||||
|
||||
member this.AddEventMemHook(callback: EventMemHook, eventType: Int32) =
|
||||
this.AddEventMemHook(callback, eventType, null)
|
||||
|
||||
member this.HookDel(callback: EventMemHook) =
|
||||
let callbacks = (_memEventHooks.Values |> Seq.concat).ToList()
|
||||
hookDel callbacks callback
|
||||
|
||||
member this.AddInHook(callback: InHook, userData: Object) =
|
||||
let trampoline(u: IntPtr) (port: Int32) (size: Int32) (user: IntPtr) =
|
||||
_inHooks
|
||||
|> Seq.map(fun (callback, userData) -> callback.Invoke(this, port, size, userData))
|
||||
|> Seq.last
|
||||
|
||||
if _inHooks |> Seq.isEmpty then
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new InHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_IN) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
_inHooks.Add(callback, userData)
|
||||
|
||||
member this.AddInHook(callback: InHook) =
|
||||
this.AddInHook(callback, null)
|
||||
|
||||
member this.AddOutHook(callback: OutHook, userData: Object) =
|
||||
let trampoline(u: IntPtr) (port: Int32) (size: Int32) (value: Int32) (user: IntPtr) =
|
||||
_outHooks
|
||||
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, port, size, value, userData))
|
||||
|
||||
if _outHooks |> Seq.isEmpty then
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new OutHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_OUT) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
_outHooks.Add(callback, userData)
|
||||
|
||||
member this.AddOutHook(callback: OutHook) =
|
||||
this.AddOutHook(callback, null)
|
||||
|
||||
member this.AddSyscallHook(callback: SyscallHook, userData: Object) =
|
||||
let trampoline(u: IntPtr) (user: IntPtr) =
|
||||
_syscallHooks
|
||||
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, userData))
|
||||
|
||||
if _syscallHooks |> Seq.isEmpty then
|
||||
let funcPointer = Marshal.GetFunctionPointerForDelegate(new SyscallHookInternal(trampoline))
|
||||
let hh = new UIntPtr(allocate(IntPtr.Size))
|
||||
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_SYSCALL) |> this.CheckResult with
|
||||
| Some e -> raise e | None -> ()
|
||||
|
||||
_syscallHooks.Add(callback, userData)
|
||||
|
||||
member this.AddSyscallHook(callback: SyscallHook) =
|
||||
this.AddSyscallHook(callback, null)
|
||||
|
||||
member this.Version() =
|
||||
let (major, minor) = (new UIntPtr(), new UIntPtr())
|
||||
let combined = binding.Version(major, minor)
|
||||
(major.ToUInt32(), minor.ToUInt32(), combined)
|
||||
|
||||
abstract Dispose : Boolean -> unit
|
||||
default this.Dispose(disposing: Boolean) =
|
||||
if (disposing) then
|
||||
// free managed resources, this is the default dispose implementation pattern
|
||||
()
|
||||
|
||||
_disposablePointers
|
||||
|> Seq.filter(fun pointer -> pointer <> IntPtr.Zero)
|
||||
|> Seq.iter Marshal.FreeHGlobal
|
||||
_disposablePointers.Clear()
|
||||
|
||||
member this.Dispose() =
|
||||
this.Dispose(true)
|
||||
GC.SuppressFinalize(this)
|
||||
|
||||
override this.Finalize() =
|
||||
this.Dispose(false)
|
||||
|
||||
interface IDisposable with
|
||||
member this.Dispose() =
|
||||
this.Dispose()
|
||||
@@ -3,8 +3,8 @@ using Gee.External.Capstone.X86;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using UnicornManaged;
|
||||
using UnicornManaged.Const;
|
||||
using UnicornEngine;
|
||||
using UnicornEngine.Const;
|
||||
|
||||
namespace UnicornSamples
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<AssemblyName>UnicornSamples</AssemblyName>
|
||||
<Copyright>Copyright © Antonio Parata 2016</Copyright>
|
||||
<RepositoryUrl>https://github.com/unicorn-engine/unicorn</RepositoryUrl>
|
||||
<Version>2.0.0</Version>
|
||||
<Version>2.0.2-rc1</Version>
|
||||
<ProjectGuid>{B80B5987-1E24-4309-8BF9-C4F91270F21C}</ProjectGuid>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
@@ -17,9 +17,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UnicornManaged\UnicornManaged.fsproj">
|
||||
<ProjectReference Include="..\UnicornEngine\UnicornEngine.fsproj">
|
||||
<Project>{0c21f1c1-2725-4a46-9022-1905f85822a5}</Project>
|
||||
<Name>UnicornManaged</Name>
|
||||
<Name>UnicornEngine</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ using Gee.External.Capstone.X86;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using UnicornManaged;
|
||||
using UnicornManaged.Const;
|
||||
using UnicornEngine;
|
||||
using UnicornEngine.Const;
|
||||
|
||||
namespace UnicornSamples
|
||||
{
|
||||
|
||||
@@ -4,13 +4,13 @@ const (
|
||||
API_MAJOR = 2
|
||||
|
||||
API_MINOR = 0
|
||||
API_PATCH = 1
|
||||
API_EXTRA = 255
|
||||
API_PATCH = 2
|
||||
API_EXTRA = 1
|
||||
VERSION_MAJOR = 2
|
||||
|
||||
VERSION_MINOR = 0
|
||||
VERSION_PATCH = 1
|
||||
VERSION_EXTRA = 255
|
||||
VERSION_PATCH = 2
|
||||
VERSION_EXTRA = 1
|
||||
SECOND_SCALE = 1000000
|
||||
MILISECOND_SCALE = 1000
|
||||
ARCH_ARM = 1
|
||||
|
||||
@@ -6,13 +6,13 @@ public interface UnicornConst {
|
||||
public static final int UC_API_MAJOR = 2;
|
||||
|
||||
public static final int UC_API_MINOR = 0;
|
||||
public static final int UC_API_PATCH = 1;
|
||||
public static final int UC_API_EXTRA = 255;
|
||||
public static final int UC_API_PATCH = 2;
|
||||
public static final int UC_API_EXTRA = 1;
|
||||
public static final int UC_VERSION_MAJOR = 2;
|
||||
|
||||
public static final int UC_VERSION_MINOR = 0;
|
||||
public static final int UC_VERSION_PATCH = 1;
|
||||
public static final int UC_VERSION_EXTRA = 255;
|
||||
public static final int UC_VERSION_PATCH = 2;
|
||||
public static final int UC_VERSION_EXTRA = 1;
|
||||
public static final int UC_SECOND_SCALE = 1000000;
|
||||
public static final int UC_MILISECOND_SCALE = 1000;
|
||||
public static final int UC_ARCH_ARM = 1;
|
||||
|
||||
@@ -7,13 +7,13 @@ interface
|
||||
const UC_API_MAJOR = 2;
|
||||
|
||||
UC_API_MINOR = 0;
|
||||
UC_API_PATCH = 1;
|
||||
UC_API_EXTRA = 255;
|
||||
UC_API_PATCH = 2;
|
||||
UC_API_EXTRA = 1;
|
||||
UC_VERSION_MAJOR = 2;
|
||||
|
||||
UC_VERSION_MINOR = 0;
|
||||
UC_VERSION_PATCH = 1;
|
||||
UC_VERSION_EXTRA = 255;
|
||||
UC_VERSION_PATCH = 2;
|
||||
UC_VERSION_EXTRA = 1;
|
||||
UC_SECOND_SCALE = 1000000;
|
||||
UC_MILISECOND_SCALE = 1000;
|
||||
UC_ARCH_ARM = 1;
|
||||
|
||||
@@ -8,6 +8,7 @@ import subprocess
|
||||
import shutil
|
||||
import sys
|
||||
import platform
|
||||
import setuptools
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import setup
|
||||
@@ -29,7 +30,7 @@ SRC_DIR = os.path.join(ROOT_DIR, 'src')
|
||||
UC_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..')
|
||||
BUILD_DIR = os.path.join(UC_DIR, 'build_python')
|
||||
|
||||
VERSION = "2.0.1.post1"
|
||||
VERSION = "2.0.2"
|
||||
|
||||
if SYSTEM == 'darwin':
|
||||
LIBRARY_FILE = "libunicorn.2.dylib"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
|
||||
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const
|
||||
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const
|
||||
from .unicorn_const import *
|
||||
from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__
|
||||
|
||||
@@ -94,7 +94,7 @@ _path_list = [os.getenv('LIBUNICORN_PATH', None),
|
||||
|
||||
for _path in _path_list:
|
||||
if _path is None: continue
|
||||
_uc = _load_lib(_path, _lib.get(sys.platform, "libunicorn.so"))
|
||||
_uc = _load_lib(_path, _lib.get(sys.platform, "libunicorn.so.2"))
|
||||
if _uc is not None:
|
||||
break
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
UC_API_MAJOR = 2
|
||||
|
||||
UC_API_MINOR = 0
|
||||
UC_API_PATCH = 1
|
||||
UC_API_EXTRA = 255
|
||||
UC_API_PATCH = 2
|
||||
UC_API_EXTRA = 1
|
||||
UC_VERSION_MAJOR = 2
|
||||
|
||||
UC_VERSION_MINOR = 0
|
||||
UC_VERSION_PATCH = 1
|
||||
UC_VERSION_EXTRA = 255
|
||||
UC_VERSION_PATCH = 2
|
||||
UC_VERSION_EXTRA = 1
|
||||
UC_SECOND_SCALE = 1000000
|
||||
UC_MILISECOND_SCALE = 1000
|
||||
UC_ARCH_ARM = 1
|
||||
|
||||
@@ -4,13 +4,13 @@ module UnicornEngine
|
||||
UC_API_MAJOR = 2
|
||||
|
||||
UC_API_MINOR = 0
|
||||
UC_API_PATCH = 1
|
||||
UC_API_EXTRA = 255
|
||||
UC_API_PATCH = 2
|
||||
UC_API_EXTRA = 1
|
||||
UC_VERSION_MAJOR = 2
|
||||
|
||||
UC_VERSION_MINOR = 0
|
||||
UC_VERSION_PATCH = 1
|
||||
UC_VERSION_EXTRA = 255
|
||||
UC_VERSION_PATCH = 2
|
||||
UC_VERSION_EXTRA = 1
|
||||
UC_SECOND_SCALE = 1000000
|
||||
UC_MILISECOND_SCALE = 1000
|
||||
UC_ARCH_ARM = 1
|
||||
|
||||
@@ -84,6 +84,43 @@ fn build_with_cmake() {
|
||||
config.generator("Ninja");
|
||||
}
|
||||
|
||||
let mut archs = String::new();
|
||||
|
||||
if std::env::var("CARGO_FEATURE_ARCH_X86").is_ok() {
|
||||
archs.push_str("x86;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_ARM").is_ok() {
|
||||
archs.push_str("arm;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_AARCH64").is_ok() {
|
||||
archs.push_str("aarch64;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_RISCV").is_ok() {
|
||||
archs.push_str("riscv;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_MIPS").is_ok() {
|
||||
archs.push_str("mips;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_SPARC").is_ok() {
|
||||
archs.push_str("sparc;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_M68K").is_ok() {
|
||||
archs.push_str("m68k;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_PPC").is_ok() {
|
||||
archs.push_str("ppc;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_S390X").is_ok() {
|
||||
archs.push_str("s390x;");
|
||||
}
|
||||
if std::env::var("CARGO_FEATURE_ARCH_TRICORE").is_ok() {
|
||||
archs.push_str("tricore;");
|
||||
}
|
||||
|
||||
if !archs.is_empty() {
|
||||
archs.pop();
|
||||
}
|
||||
|
||||
// need to clear build target and append "build" to the path because
|
||||
// unicorn's CMakeLists.txt doesn't properly support 'install', so we use
|
||||
// the build artifacts from the build directory, which cmake crate sets
|
||||
@@ -91,6 +128,7 @@ fn build_with_cmake() {
|
||||
let dst = config
|
||||
.define("UNICORN_BUILD_TESTS", "OFF")
|
||||
.define("UNICORN_INSTALL", "OFF")
|
||||
.define("UNICORN_ARCH", archs)
|
||||
.no_build_target(true)
|
||||
.build();
|
||||
println!(
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::Unicorn;
|
||||
use crate::{Unicorn, UnicornInner};
|
||||
|
||||
use super::unicorn_const::{uc_error, Arch, HookType, MemRegion, MemType, Mode, Query};
|
||||
use core::ffi::c_void;
|
||||
use alloc::rc::Weak;
|
||||
use core::{cell::UnsafeCell, ffi::c_void};
|
||||
use libc::{c_char, c_int};
|
||||
|
||||
pub type uc_handle = *mut c_void;
|
||||
@@ -89,7 +90,7 @@ extern "C" {
|
||||
|
||||
pub struct UcHook<'a, D: 'a, F: 'a> {
|
||||
pub callback: F,
|
||||
pub uc: Unicorn<'a, D>,
|
||||
pub uc: Weak<UnsafeCell<UnicornInner<'a, D>>>,
|
||||
}
|
||||
|
||||
pub trait IsUcHook<'a> {}
|
||||
@@ -106,8 +107,11 @@ where
|
||||
F: FnMut(&mut crate::Unicorn<D>, u64, usize) -> u64,
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc, offset, size)
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc, offset, size)
|
||||
}
|
||||
|
||||
pub extern "C" fn mmio_write_callback_proxy<D, F>(
|
||||
@@ -120,8 +124,11 @@ pub extern "C" fn mmio_write_callback_proxy<D, F>(
|
||||
F: FnMut(&mut crate::Unicorn<D>, u64, usize, u64),
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc, offset, size, value);
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc, offset, size, value);
|
||||
}
|
||||
|
||||
pub extern "C" fn code_hook_proxy<D, F>(
|
||||
@@ -133,8 +140,11 @@ pub extern "C" fn code_hook_proxy<D, F>(
|
||||
F: FnMut(&mut crate::Unicorn<D>, u64, u32),
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc, address, size);
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc, address, size);
|
||||
}
|
||||
|
||||
pub extern "C" fn block_hook_proxy<D, F>(
|
||||
@@ -146,8 +156,11 @@ pub extern "C" fn block_hook_proxy<D, F>(
|
||||
F: FnMut(&mut crate::Unicorn<D>, u64, u32),
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc, address, size);
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc, address, size);
|
||||
}
|
||||
|
||||
pub extern "C" fn mem_hook_proxy<D, F>(
|
||||
@@ -162,8 +175,11 @@ where
|
||||
F: FnMut(&mut crate::Unicorn<D>, MemType, u64, usize, i64) -> bool,
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc, mem_type, address, size as usize, value)
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc, mem_type, address, size as usize, value)
|
||||
}
|
||||
|
||||
pub extern "C" fn intr_hook_proxy<D, F>(uc: uc_handle, value: u32, user_data: *mut UcHook<D, F>)
|
||||
@@ -171,8 +187,11 @@ where
|
||||
F: FnMut(&mut crate::Unicorn<D>, u32),
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc, value);
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc, value);
|
||||
}
|
||||
|
||||
pub extern "C" fn insn_in_hook_proxy<D, F>(
|
||||
@@ -180,12 +199,16 @@ pub extern "C" fn insn_in_hook_proxy<D, F>(
|
||||
port: u32,
|
||||
size: usize,
|
||||
user_data: *mut UcHook<D, F>,
|
||||
) where
|
||||
) -> u32
|
||||
where
|
||||
F: FnMut(&mut crate::Unicorn<D>, u32, usize) -> u32,
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc, port, size);
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc, port, size)
|
||||
}
|
||||
|
||||
pub extern "C" fn insn_invalid_hook_proxy<D, F>(uc: uc_handle, user_data: *mut UcHook<D, F>) -> bool
|
||||
@@ -193,8 +216,11 @@ where
|
||||
F: FnMut(&mut crate::Unicorn<D>) -> bool,
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc)
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc)
|
||||
}
|
||||
|
||||
pub extern "C" fn insn_out_hook_proxy<D, F>(
|
||||
@@ -207,8 +233,11 @@ pub extern "C" fn insn_out_hook_proxy<D, F>(
|
||||
F: FnMut(&mut crate::Unicorn<D>, u32, usize, u32),
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc, port, size, value);
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc, port, size, value);
|
||||
}
|
||||
|
||||
pub extern "C" fn insn_sys_hook_proxy<D, F>(uc: uc_handle, user_data: *mut UcHook<D, F>)
|
||||
@@ -216,6 +245,9 @@ where
|
||||
F: FnMut(&mut crate::Unicorn<D>),
|
||||
{
|
||||
let user_data = unsafe { &mut *user_data };
|
||||
debug_assert_eq!(uc, user_data.uc.get_handle());
|
||||
(user_data.callback)(&mut user_data.uc);
|
||||
let mut user_data_uc = Unicorn {
|
||||
inner: user_data.uc.upgrade().unwrap(),
|
||||
};
|
||||
debug_assert_eq!(uc, user_data_uc.get_handle());
|
||||
(user_data.callback)(&mut user_data_uc);
|
||||
}
|
||||
|
||||
@@ -369,17 +369,13 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut read_data = read_callback.map(|c| {
|
||||
Box::new(ffi::UcHook {
|
||||
callback: c,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
})
|
||||
});
|
||||
let mut write_data = write_callback.map(|c| {
|
||||
Box::new(ffi::UcHook {
|
||||
callback: c,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
})
|
||||
});
|
||||
|
||||
@@ -388,12 +384,18 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
self.get_handle(),
|
||||
address,
|
||||
size,
|
||||
ffi::mmio_read_callback_proxy::<D, R> as _,
|
||||
match read_data {
|
||||
Some(_) => ffi::mmio_read_callback_proxy::<D, R> as _,
|
||||
None => ptr::null_mut(),
|
||||
},
|
||||
match read_data {
|
||||
Some(ref mut d) => d.as_mut() as *mut _ as _,
|
||||
None => ptr::null_mut(),
|
||||
},
|
||||
ffi::mmio_write_callback_proxy::<D, W> as _,
|
||||
match write_data {
|
||||
Some(_) => ffi::mmio_write_callback_proxy::<D, W> as _,
|
||||
None => ptr::null_mut(),
|
||||
},
|
||||
match write_data {
|
||||
Some(ref mut d) => d.as_mut() as *mut _ as _,
|
||||
None => ptr::null_mut(),
|
||||
@@ -586,7 +588,8 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
return Err(uc_error::ARCH);
|
||||
}
|
||||
|
||||
let err: uc_error = unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) };
|
||||
let err: uc_error =
|
||||
unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) };
|
||||
|
||||
if err == uc_error::OK {
|
||||
boxed = value.into_boxed_slice();
|
||||
@@ -622,9 +625,7 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut hook_ptr = core::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::UcHook {
|
||||
callback,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
@@ -654,9 +655,7 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut hook_ptr = core::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::UcHook {
|
||||
callback,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
@@ -697,9 +696,7 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut hook_ptr = core::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::UcHook {
|
||||
callback,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
@@ -730,9 +727,7 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut hook_ptr = core::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::UcHook {
|
||||
callback,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
@@ -763,9 +758,7 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut hook_ptr = core::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::UcHook {
|
||||
callback,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
@@ -796,9 +789,7 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut hook_ptr = core::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::UcHook {
|
||||
callback,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
@@ -830,9 +821,7 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut hook_ptr = core::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::UcHook {
|
||||
callback,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
@@ -870,9 +859,7 @@ impl<'a, D> Unicorn<'a, D> {
|
||||
let mut hook_ptr = core::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::UcHook {
|
||||
callback,
|
||||
uc: Unicorn {
|
||||
inner: self.inner.clone(),
|
||||
},
|
||||
uc: Rc::downgrade(&self.inner),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
|
||||
Reference in New Issue
Block a user