mirror of
https://github.com/Cxbx-Reloaded/unicorn.git
synced 2024-12-13 05:56:09 +00:00
Merge pull request #294 from xorstream/msvc_support
Added MSVC++ support for unicorn
This commit is contained in:
commit
0e5bc9f84c
1
.gitignore
vendored
1
.gitignore
vendored
@ -77,6 +77,7 @@ unicorn.pc
|
||||
unicorn.lib
|
||||
unicorn.dll
|
||||
unicorn_*.lib
|
||||
unicorn_*.exp
|
||||
unicorn_*.dll
|
||||
|
||||
|
||||
|
77
bindings/msvc/README.TXT
Normal file
77
bindings/msvc/README.TXT
Normal file
@ -0,0 +1,77 @@
|
||||
This documentation explains how to use Unicorn with Microsoft Visual C++ (MSVC).
|
||||
This will not build the Unicorn Engine itself, it just allows you to use the
|
||||
prebuilt Windows binaries when writing projects in Microsoft Visual C++.
|
||||
|
||||
The prebuilt windows binaries can be found under the "Windows Core engine"
|
||||
heading on the following page. Be sure to use the 32bit package when making
|
||||
32bit applications (even in 64bit windows). And use the 64bit package to
|
||||
build 64bit applications.
|
||||
http://www.unicorn-engine.org/download/
|
||||
|
||||
|
||||
|
||||
It is not possible to use the prebuilt static Unicorn library, unicorn.lib,
|
||||
with Microsoft Visual C++ because it will complain about a bunch of missing
|
||||
functions, variables etc.
|
||||
|
||||
We therefore use the prebuilt dynamic Unicorn library, unicorn.dll.
|
||||
There are two ways to use this with your Microsoft Visual C++ project:
|
||||
1) By dynamically linking the dll into your project.
|
||||
2) By statically linking the dll into your project.
|
||||
|
||||
|
||||
|
||||
:: 1) Dynamic Linking
|
||||
|
||||
The files unicorn_dynload.c and unicorn_dynload.h are used for dynamic linking.
|
||||
Ensure that unicorn_dynload.h is in the main unicorn includes directory.
|
||||
(It should be in the same directory as "unicorn.h".)
|
||||
Then include unicorn_dynload.c in your project so that it gets build along
|
||||
with your other project files. You could alternatively compile it first into a
|
||||
static library and then link that library into your project.
|
||||
|
||||
Now where you would normally include "unicorn.h" in your project you instead
|
||||
include "unicorn_dynload.h". You should also define DYNLOAD above the include
|
||||
of "unicorn_dynload.h", or instead add DYNLOAD to your project settings in:
|
||||
Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions.
|
||||
|
||||
Some example code for including this header is as follows:
|
||||
|
||||
#define DYNLOAD 1
|
||||
|
||||
#ifdef DYNLOAD
|
||||
#include <unicorn/unicorn_dynload.h>
|
||||
#else
|
||||
#include <unicorn/unicorn.h>
|
||||
#endif
|
||||
|
||||
Now build your application as normal.
|
||||
|
||||
|
||||
|
||||
:: 2) Static Linking
|
||||
|
||||
To perform static linking of unicorn.dll, you need to first generate some
|
||||
static import libraries. To do this run "make_staload.bat".
|
||||
You may need to edit the first line in "make_staload.bat" to point to the
|
||||
location of your "vcvars32.bat" file. This will build separate import libraries
|
||||
for importing the 32bit or 64bit version of the dlls.
|
||||
unicorn_staload.lib is used to link to the 32bit version of unicorn.dll.
|
||||
unicorn_staload64.lib is used to link to the 64bit version of unicorn.dll.
|
||||
|
||||
Now you make a unicorn project like usual, including "unicorn.h", and
|
||||
then you need to also link in "unicorn_staload.lib" or "unicorn_staload64.lib".
|
||||
|
||||
The first step to doing this is to make sure the directory that contains
|
||||
"unicorn_staload.lib" is added to your project by adding it in:
|
||||
Configuration Properties -> C/C++ -> Linker -> General -> Additional Library Directories
|
||||
(So for example add here "C:\unicorn\bindings\msvc" if that is where they are)
|
||||
|
||||
The second step is to link in the library. You can do this by either adding
|
||||
this line to your C sourcecode:
|
||||
#pragma comment(lib, "unicorn_staload.lib")
|
||||
|
||||
Or by adding "unicorn_staload.lib" to your project in:
|
||||
Configuration Properties -> C/C++ -> Linker -> Input -> Additional Dependencies
|
||||
|
||||
|
3
bindings/msvc/make_staload.bat
Normal file
3
bindings/msvc/make_staload.bat
Normal file
@ -0,0 +1,3 @@
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\vcvars32.bat"
|
||||
lib /DEF:unicorn.def /OUT:unicorn_staload.lib /MACHINE:X86
|
||||
lib /DEF:unicorn.def /OUT:unicorn_staload64.lib /MACHINE:X64
|
18
bindings/msvc/unicorn.def
Normal file
18
bindings/msvc/unicorn.def
Normal file
@ -0,0 +1,18 @@
|
||||
EXPORTS
|
||||
uc_version
|
||||
uc_arch_supported
|
||||
uc_open
|
||||
uc_close
|
||||
uc_errno
|
||||
uc_strerror
|
||||
uc_reg_write
|
||||
uc_reg_read
|
||||
uc_mem_write
|
||||
uc_mem_read
|
||||
uc_emu_start
|
||||
uc_emu_stop
|
||||
uc_hook_add
|
||||
uc_hook_del
|
||||
uc_mem_map
|
||||
uc_mem_unmap
|
||||
uc_mem_protect
|
249
bindings/msvc/unicorn_dynload.c
Normal file
249
bindings/msvc/unicorn_dynload.c
Normal file
@ -0,0 +1,249 @@
|
||||
//
|
||||
// Dynamic loader for unicorn shared library in windows and linux.
|
||||
// This was made for v0.9 of unicorn.
|
||||
// Newer versions of unicorn may require changes to these files.
|
||||
//
|
||||
// Windows Notes:
|
||||
// If an absolute path to unicorn.dll is passed into uc_dyn_load() it will
|
||||
// still try to load the rest of the dependent dlls (ie libglib-2.0-0.dll etc)
|
||||
// from standard dll paths. This is usually the directory that the main
|
||||
// exe file, that loaded unicorn.dll, is in. This is standard behaviour for
|
||||
// Windows dll files, and not specific to unicorn dlls.
|
||||
//
|
||||
// So putting all dlls in their own directory and then attempting to load
|
||||
// unicorn.dll from that directory via an absolute path will cause
|
||||
// uc_dyn_load() to fail.
|
||||
//
|
||||
// The easiest way around this is to place all dlls in the same directory
|
||||
// as your main exe file. Other ways around this are using various flags
|
||||
// for LoadLibraryEx() or by calling SetDllDirectory().
|
||||
//
|
||||
// LoadLibraryEx info:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
||||
// SetDllDirectory() info:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686203(v=vs.85).aspx
|
||||
//
|
||||
// Zak Escano - November 2015
|
||||
//
|
||||
|
||||
// This is to detect whether we are loading a dll in windows or a so in linux.
|
||||
#ifdef _MSC_VER
|
||||
#define WINDOWS_DLL 1
|
||||
#endif
|
||||
|
||||
#include <unicorn/unicorn_dynload.h>
|
||||
|
||||
#ifdef WINDOWS_DLL
|
||||
#include <Windows.h>
|
||||
#define DYNLOAD_DEFPATH "unicorn.dll"
|
||||
#define DYNLOAD_HANDLE HMODULE
|
||||
#define DYNLOAD_LOADLIB(path, f)LoadLibraryEx(path, NULL, f)
|
||||
#define DYNLOAD_FREELIB(handle) FreeLibrary(handle)
|
||||
#define DYNLOAD_GETFUNC(h, n) GetProcAddress(h, n)
|
||||
#define DYNLOAD_GETERROR() GetLastError()
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#define DYNLOAD_DEFPATH "unicorn.so"
|
||||
#define DYNLOAD_HANDLE void*
|
||||
#define DYNLOAD_LOADLIB(path, f)dlopen(path, f)
|
||||
#define DYNLOAD_FREELIB(handle) dlclose(handle)
|
||||
#define DYNLOAD_GETFUNC(h, n) dlsym(h, n)
|
||||
#define DYNLOAD_GETERROR() dlerror()
|
||||
#endif
|
||||
|
||||
|
||||
static DYNLOAD_HANDLE g_dyn_handle = NULL;
|
||||
|
||||
|
||||
typedef unsigned int (*uc_version_t)(unsigned int *major, unsigned int *minor);
|
||||
typedef bool (*uc_arch_supported_t)(uc_arch arch);
|
||||
typedef uc_err (*uc_open_t)(uc_arch arch, uc_mode mode, uc_engine **uc);
|
||||
typedef uc_err (*uc_close_t)(uc_engine *uc);
|
||||
typedef uc_err (*uc_errno_t)(uc_engine *uc);
|
||||
typedef const char* (*uc_strerror_t)(uc_err code);
|
||||
typedef uc_err (*uc_reg_write_t)(uc_engine *uc, int regid, const void *value);
|
||||
typedef uc_err (*uc_reg_read_t)(uc_engine *uc, int regid, void *value);
|
||||
typedef uc_err (*uc_mem_write_t)(uc_engine *uc, uint64_t address, const void *bytes, size_t size);
|
||||
typedef uc_err (*uc_mem_read_t)(uc_engine *uc, uint64_t address, void *bytes, size_t size);
|
||||
typedef uc_err (*uc_emu_start_t)(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);
|
||||
typedef uc_err (*uc_emu_stop_t)(uc_engine *uc);
|
||||
typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...);
|
||||
typedef uc_err (*uc_hook_del_t)(uc_engine *uc, uc_hook hh);
|
||||
typedef uc_err (*uc_mem_map_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||
typedef uc_err (*uc_mem_unmap_t)(uc_engine *uc, uint64_t address, size_t size);
|
||||
typedef uc_err (*uc_mem_protect_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||
|
||||
|
||||
static uc_version_t gp_uc_version = NULL;
|
||||
static uc_arch_supported_t gp_uc_arch_supported = NULL;
|
||||
static uc_open_t gp_uc_open = NULL;
|
||||
static uc_close_t gp_uc_close = NULL;
|
||||
static uc_errno_t gp_uc_errno = NULL;
|
||||
static uc_strerror_t gp_uc_strerror = NULL;
|
||||
static uc_reg_write_t gp_uc_reg_write = NULL;
|
||||
static uc_reg_read_t gp_uc_reg_read = NULL;
|
||||
static uc_mem_write_t gp_uc_mem_write = NULL;
|
||||
static uc_mem_read_t gp_uc_mem_read = NULL;
|
||||
static uc_emu_start_t gp_uc_emu_start = NULL;
|
||||
static uc_emu_stop_t gp_uc_emu_stop = NULL;
|
||||
static uc_hook_add_t gp_uc_hook_add = NULL;
|
||||
static uc_hook_del_t gp_uc_hook_del = NULL;
|
||||
static uc_mem_map_t gp_uc_mem_map = NULL;
|
||||
static uc_mem_unmap_t gp_uc_mem_unmap = NULL;
|
||||
static uc_mem_protect_t gp_uc_mem_protect = NULL;
|
||||
|
||||
|
||||
bool uc_dyn_load(const char* path, int flags)
|
||||
{
|
||||
if( path == NULL )
|
||||
{
|
||||
path = DYNLOAD_DEFPATH;
|
||||
}
|
||||
|
||||
if( g_dyn_handle )
|
||||
{
|
||||
if( !uc_dyn_free() )
|
||||
return false;
|
||||
}
|
||||
|
||||
g_dyn_handle = DYNLOAD_LOADLIB(path, flags);
|
||||
if( g_dyn_handle == NULL )
|
||||
{
|
||||
//int err = DYNLOAD_GETERROR();
|
||||
//printf("Error loading %s: Last error is %X\n", path, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_uc_version = (uc_version_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_version");
|
||||
gp_uc_arch_supported = (uc_arch_supported_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_arch_supported");
|
||||
gp_uc_open = (uc_open_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_open");
|
||||
gp_uc_close = (uc_close_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_close");
|
||||
gp_uc_errno = (uc_errno_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_errno");
|
||||
gp_uc_strerror = (uc_strerror_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_strerror");
|
||||
gp_uc_reg_write = (uc_reg_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_write");
|
||||
gp_uc_reg_read = (uc_reg_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_read");
|
||||
gp_uc_mem_write = (uc_mem_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_write");
|
||||
gp_uc_mem_read = (uc_mem_read_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_read");
|
||||
gp_uc_emu_start = (uc_emu_start_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_start");
|
||||
gp_uc_emu_stop = (uc_emu_stop_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_emu_stop");
|
||||
gp_uc_hook_add = (uc_hook_add_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_add");
|
||||
gp_uc_hook_del = (uc_hook_del_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_del");
|
||||
gp_uc_mem_map = (uc_mem_map_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map");
|
||||
gp_uc_mem_unmap = (uc_mem_unmap_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_unmap");
|
||||
gp_uc_mem_protect = (uc_mem_protect_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_protect");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uc_dyn_free(void)
|
||||
{
|
||||
if( g_dyn_handle==NULL )
|
||||
return true;
|
||||
|
||||
DYNLOAD_FREELIB(g_dyn_handle);
|
||||
g_dyn_handle = NULL;
|
||||
|
||||
gp_uc_version = NULL;
|
||||
gp_uc_arch_supported = NULL;
|
||||
gp_uc_open = NULL;
|
||||
gp_uc_close = NULL;
|
||||
gp_uc_errno = NULL;
|
||||
gp_uc_strerror = NULL;
|
||||
gp_uc_reg_write = NULL;
|
||||
gp_uc_reg_read = NULL;
|
||||
gp_uc_mem_write = NULL;
|
||||
gp_uc_mem_read = NULL;
|
||||
gp_uc_emu_start = NULL;
|
||||
gp_uc_emu_stop = NULL;
|
||||
gp_uc_hook_add = NULL;
|
||||
gp_uc_hook_del = NULL;
|
||||
gp_uc_mem_map = NULL;
|
||||
gp_uc_mem_unmap = NULL;
|
||||
gp_uc_mem_protect = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
unsigned int uc_version(unsigned int *major, unsigned int *minor)
|
||||
{ return gp_uc_version(major, minor); }
|
||||
|
||||
bool uc_arch_supported(uc_arch arch)
|
||||
{ return gp_uc_arch_supported(arch); }
|
||||
|
||||
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc)
|
||||
{ return gp_uc_open(arch, mode, uc); }
|
||||
|
||||
uc_err uc_close(uc_engine *uc)
|
||||
{ return gp_uc_close(uc); }
|
||||
|
||||
uc_err uc_errno(uc_engine *uc)
|
||||
{ return gp_uc_errno(uc); }
|
||||
|
||||
const char *uc_strerror(uc_err code)
|
||||
{ return gp_uc_strerror(code); }
|
||||
|
||||
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)
|
||||
{ return gp_uc_reg_write(uc, regid, value); }
|
||||
|
||||
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
|
||||
{ return gp_uc_reg_read(uc, regid, value); }
|
||||
|
||||
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size)
|
||||
{ return gp_uc_mem_write(uc, address, bytes, size); }
|
||||
|
||||
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size)
|
||||
{ return gp_uc_mem_read(uc, address, bytes, size); }
|
||||
|
||||
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
|
||||
{ return gp_uc_emu_start(uc, begin, until, timeout, count); }
|
||||
|
||||
uc_err uc_emu_stop(uc_engine *uc)
|
||||
{ return gp_uc_emu_stop(uc); }
|
||||
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...)
|
||||
{
|
||||
va_list valist;
|
||||
uc_err ret = UC_ERR_OK;
|
||||
int id;
|
||||
uint64_t begin, end;
|
||||
va_start(valist, user_data);
|
||||
|
||||
switch(type) {
|
||||
default:
|
||||
break;
|
||||
case UC_HOOK_INTR:
|
||||
// 0 extra args
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data);
|
||||
break;
|
||||
case UC_HOOK_INSN:
|
||||
// 1 extra arg
|
||||
id = va_arg(valist, int);
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data, id);
|
||||
break;
|
||||
case UC_HOOK_CODE:
|
||||
case UC_HOOK_BLOCK:
|
||||
case UC_HOOK_MEM_READ:
|
||||
case UC_HOOK_MEM_WRITE:
|
||||
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
|
||||
// 2 extra arg
|
||||
begin = va_arg(valist, uint64_t);
|
||||
end = va_arg(valist, uint64_t);
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end);
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(valist);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
||||
{ return gp_uc_hook_del(uc, hh); }
|
||||
|
||||
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||
{ return gp_uc_mem_map(uc, address, size, perms); }
|
||||
|
||||
uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size)
|
||||
{ return gp_uc_mem_unmap(uc, address, size); }
|
||||
|
||||
uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||
{ return gp_uc_mem_protect(uc, address, size, perms); }
|
||||
|
67
include/unicorn/unicorn_dynload.h
Normal file
67
include/unicorn/unicorn_dynload.h
Normal file
@ -0,0 +1,67 @@
|
||||
//
|
||||
// Dynamic loader for unicorn shared library in windows and linux.
|
||||
// This was made for v0.9 of unicorn.
|
||||
// Newer versions of unicorn may require changes to these files.
|
||||
//
|
||||
// Windows Notes:
|
||||
// If an absolute path to unicorn.dll is passed into uc_dyn_load() it will
|
||||
// still try to load the rest of the dependent dlls (ie libglib-2.0-0.dll etc)
|
||||
// from standard dll paths. This is usually the directory that the main
|
||||
// exe file, that loaded unicorn.dll, is in. This is standard behaviour for
|
||||
// Windows dll files, and not specific to unicorn dlls.
|
||||
//
|
||||
// So putting all dlls in their own directory and then attempting to load
|
||||
// unicorn.dll from that directory via an absolute path will cause
|
||||
// uc_dyn_load() to fail.
|
||||
//
|
||||
// The easiest way around this is to place all dlls in the same directory
|
||||
// as your main exe file. Other ways around this are using various flags
|
||||
// for LoadLibraryEx() or by calling SetDllDirectory().
|
||||
//
|
||||
// LoadLibraryEx info:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
||||
// SetDllDirectory() info:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686203(v=vs.85).aspx
|
||||
//
|
||||
// Zak Escano - November 2015
|
||||
//
|
||||
|
||||
#ifndef _UNICORN_DYNLOAD_H_
|
||||
#define _UNICORN_DYNLOAD_H_
|
||||
|
||||
// Undefine shared here so that functions aren't defined as: "__declspec(dllexport)"
|
||||
#ifdef UNICORN_SHARED
|
||||
#undef UNICORN_SHARED
|
||||
#endif
|
||||
#include "unicorn.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Dynamically load shared library.
|
||||
Check the notes at the top for info regarding dll file locations in windows.
|
||||
|
||||
@path: path to shared library file. (NULL to use default path)
|
||||
@flags: system specific flags for loading shared library file. (0 for default)
|
||||
|
||||
@return true on success, false if failed.
|
||||
*/
|
||||
bool uc_dyn_load(const char* path, int flags);
|
||||
|
||||
/*
|
||||
Free resources when done using shared library.
|
||||
|
||||
@return true on success, false if failed.
|
||||
*/
|
||||
bool uc_dyn_free(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _UNICORN_DYNLOAD_H_
|
||||
|
Loading…
Reference in New Issue
Block a user