diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 7e3bf2ff..0ff56f84 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -10,7 +10,6 @@ add_subdirectory("libraries/fmt") set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp) -include_directories(libraries/unicorn/include) include_directories(${source_DIR}) add_library(lightswitch SHARED @@ -24,5 +23,5 @@ add_library(lightswitch SHARED ${source_DIR}/switch/common.cpp ${source_DIR}/switch/loader/nro.cpp ) -target_link_libraries(lightswitch ${CMAKE_SOURCE_DIR}/libraries/unicorn/libunicorn.a fmt tinyxml2) +target_link_libraries(lightswitch fmt tinyxml2) target_compile_options(lightswitch PRIVATE -Wno-c++17-extensions) diff --git a/app/libraries/unicorn/include/unicorn/arm64.h b/app/libraries/unicorn/include/unicorn/arm64.h deleted file mode 100644 index fe46f159..00000000 --- a/app/libraries/unicorn/include/unicorn/arm64.h +++ /dev/null @@ -1,307 +0,0 @@ -/* Unicorn Emulator Engine */ -/* By Nguyen Anh Quynh , 2015-2017 */ -/* This file is released under LGPL2. - See COPYING.LGPL2 in root directory for more details -*/ - -#ifndef UNICORN_ARM64_H -#define UNICORN_ARM64_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _MSC_VER -#pragma warning(disable:4201) -#endif - -//> ARM64 registers -typedef enum uc_arm64_reg { - UC_ARM64_REG_INVALID = 0, - - UC_ARM64_REG_X29, - UC_ARM64_REG_X30, - UC_ARM64_REG_NZCV, - UC_ARM64_REG_SP, - UC_ARM64_REG_WSP, - UC_ARM64_REG_WZR, - UC_ARM64_REG_XZR, - UC_ARM64_REG_B0, - UC_ARM64_REG_B1, - UC_ARM64_REG_B2, - UC_ARM64_REG_B3, - UC_ARM64_REG_B4, - UC_ARM64_REG_B5, - UC_ARM64_REG_B6, - UC_ARM64_REG_B7, - UC_ARM64_REG_B8, - UC_ARM64_REG_B9, - UC_ARM64_REG_B10, - UC_ARM64_REG_B11, - UC_ARM64_REG_B12, - UC_ARM64_REG_B13, - UC_ARM64_REG_B14, - UC_ARM64_REG_B15, - UC_ARM64_REG_B16, - UC_ARM64_REG_B17, - UC_ARM64_REG_B18, - UC_ARM64_REG_B19, - UC_ARM64_REG_B20, - UC_ARM64_REG_B21, - UC_ARM64_REG_B22, - UC_ARM64_REG_B23, - UC_ARM64_REG_B24, - UC_ARM64_REG_B25, - UC_ARM64_REG_B26, - UC_ARM64_REG_B27, - UC_ARM64_REG_B28, - UC_ARM64_REG_B29, - UC_ARM64_REG_B30, - UC_ARM64_REG_B31, - UC_ARM64_REG_D0, - UC_ARM64_REG_D1, - UC_ARM64_REG_D2, - UC_ARM64_REG_D3, - UC_ARM64_REG_D4, - UC_ARM64_REG_D5, - UC_ARM64_REG_D6, - UC_ARM64_REG_D7, - UC_ARM64_REG_D8, - UC_ARM64_REG_D9, - UC_ARM64_REG_D10, - UC_ARM64_REG_D11, - UC_ARM64_REG_D12, - UC_ARM64_REG_D13, - UC_ARM64_REG_D14, - UC_ARM64_REG_D15, - UC_ARM64_REG_D16, - UC_ARM64_REG_D17, - UC_ARM64_REG_D18, - UC_ARM64_REG_D19, - UC_ARM64_REG_D20, - UC_ARM64_REG_D21, - UC_ARM64_REG_D22, - UC_ARM64_REG_D23, - UC_ARM64_REG_D24, - UC_ARM64_REG_D25, - UC_ARM64_REG_D26, - UC_ARM64_REG_D27, - UC_ARM64_REG_D28, - UC_ARM64_REG_D29, - UC_ARM64_REG_D30, - UC_ARM64_REG_D31, - UC_ARM64_REG_H0, - UC_ARM64_REG_H1, - UC_ARM64_REG_H2, - UC_ARM64_REG_H3, - UC_ARM64_REG_H4, - UC_ARM64_REG_H5, - UC_ARM64_REG_H6, - UC_ARM64_REG_H7, - UC_ARM64_REG_H8, - UC_ARM64_REG_H9, - UC_ARM64_REG_H10, - UC_ARM64_REG_H11, - UC_ARM64_REG_H12, - UC_ARM64_REG_H13, - UC_ARM64_REG_H14, - UC_ARM64_REG_H15, - UC_ARM64_REG_H16, - UC_ARM64_REG_H17, - UC_ARM64_REG_H18, - UC_ARM64_REG_H19, - UC_ARM64_REG_H20, - UC_ARM64_REG_H21, - UC_ARM64_REG_H22, - UC_ARM64_REG_H23, - UC_ARM64_REG_H24, - UC_ARM64_REG_H25, - UC_ARM64_REG_H26, - UC_ARM64_REG_H27, - UC_ARM64_REG_H28, - UC_ARM64_REG_H29, - UC_ARM64_REG_H30, - UC_ARM64_REG_H31, - UC_ARM64_REG_Q0, - UC_ARM64_REG_Q1, - UC_ARM64_REG_Q2, - UC_ARM64_REG_Q3, - UC_ARM64_REG_Q4, - UC_ARM64_REG_Q5, - UC_ARM64_REG_Q6, - UC_ARM64_REG_Q7, - UC_ARM64_REG_Q8, - UC_ARM64_REG_Q9, - UC_ARM64_REG_Q10, - UC_ARM64_REG_Q11, - UC_ARM64_REG_Q12, - UC_ARM64_REG_Q13, - UC_ARM64_REG_Q14, - UC_ARM64_REG_Q15, - UC_ARM64_REG_Q16, - UC_ARM64_REG_Q17, - UC_ARM64_REG_Q18, - UC_ARM64_REG_Q19, - UC_ARM64_REG_Q20, - UC_ARM64_REG_Q21, - UC_ARM64_REG_Q22, - UC_ARM64_REG_Q23, - UC_ARM64_REG_Q24, - UC_ARM64_REG_Q25, - UC_ARM64_REG_Q26, - UC_ARM64_REG_Q27, - UC_ARM64_REG_Q28, - UC_ARM64_REG_Q29, - UC_ARM64_REG_Q30, - UC_ARM64_REG_Q31, - UC_ARM64_REG_S0, - UC_ARM64_REG_S1, - UC_ARM64_REG_S2, - UC_ARM64_REG_S3, - UC_ARM64_REG_S4, - UC_ARM64_REG_S5, - UC_ARM64_REG_S6, - UC_ARM64_REG_S7, - UC_ARM64_REG_S8, - UC_ARM64_REG_S9, - UC_ARM64_REG_S10, - UC_ARM64_REG_S11, - UC_ARM64_REG_S12, - UC_ARM64_REG_S13, - UC_ARM64_REG_S14, - UC_ARM64_REG_S15, - UC_ARM64_REG_S16, - UC_ARM64_REG_S17, - UC_ARM64_REG_S18, - UC_ARM64_REG_S19, - UC_ARM64_REG_S20, - UC_ARM64_REG_S21, - UC_ARM64_REG_S22, - UC_ARM64_REG_S23, - UC_ARM64_REG_S24, - UC_ARM64_REG_S25, - UC_ARM64_REG_S26, - UC_ARM64_REG_S27, - UC_ARM64_REG_S28, - UC_ARM64_REG_S29, - UC_ARM64_REG_S30, - UC_ARM64_REG_S31, - UC_ARM64_REG_W0, - UC_ARM64_REG_W1, - UC_ARM64_REG_W2, - UC_ARM64_REG_W3, - UC_ARM64_REG_W4, - UC_ARM64_REG_W5, - UC_ARM64_REG_W6, - UC_ARM64_REG_W7, - UC_ARM64_REG_W8, - UC_ARM64_REG_W9, - UC_ARM64_REG_W10, - UC_ARM64_REG_W11, - UC_ARM64_REG_W12, - UC_ARM64_REG_W13, - UC_ARM64_REG_W14, - UC_ARM64_REG_W15, - UC_ARM64_REG_W16, - UC_ARM64_REG_W17, - UC_ARM64_REG_W18, - UC_ARM64_REG_W19, - UC_ARM64_REG_W20, - UC_ARM64_REG_W21, - UC_ARM64_REG_W22, - UC_ARM64_REG_W23, - UC_ARM64_REG_W24, - UC_ARM64_REG_W25, - UC_ARM64_REG_W26, - UC_ARM64_REG_W27, - UC_ARM64_REG_W28, - UC_ARM64_REG_W29, - UC_ARM64_REG_W30, - UC_ARM64_REG_X0, - UC_ARM64_REG_X1, - UC_ARM64_REG_X2, - UC_ARM64_REG_X3, - UC_ARM64_REG_X4, - UC_ARM64_REG_X5, - UC_ARM64_REG_X6, - UC_ARM64_REG_X7, - UC_ARM64_REG_X8, - UC_ARM64_REG_X9, - UC_ARM64_REG_X10, - UC_ARM64_REG_X11, - UC_ARM64_REG_X12, - UC_ARM64_REG_X13, - UC_ARM64_REG_X14, - UC_ARM64_REG_X15, - UC_ARM64_REG_X16, - UC_ARM64_REG_X17, - UC_ARM64_REG_X18, - UC_ARM64_REG_X19, - UC_ARM64_REG_X20, - UC_ARM64_REG_X21, - UC_ARM64_REG_X22, - UC_ARM64_REG_X23, - UC_ARM64_REG_X24, - UC_ARM64_REG_X25, - UC_ARM64_REG_X26, - UC_ARM64_REG_X27, - UC_ARM64_REG_X28, - - UC_ARM64_REG_V0, - UC_ARM64_REG_V1, - UC_ARM64_REG_V2, - UC_ARM64_REG_V3, - UC_ARM64_REG_V4, - UC_ARM64_REG_V5, - UC_ARM64_REG_V6, - UC_ARM64_REG_V7, - UC_ARM64_REG_V8, - UC_ARM64_REG_V9, - UC_ARM64_REG_V10, - UC_ARM64_REG_V11, - UC_ARM64_REG_V12, - UC_ARM64_REG_V13, - UC_ARM64_REG_V14, - UC_ARM64_REG_V15, - UC_ARM64_REG_V16, - UC_ARM64_REG_V17, - UC_ARM64_REG_V18, - UC_ARM64_REG_V19, - UC_ARM64_REG_V20, - UC_ARM64_REG_V21, - UC_ARM64_REG_V22, - UC_ARM64_REG_V23, - UC_ARM64_REG_V24, - UC_ARM64_REG_V25, - UC_ARM64_REG_V26, - UC_ARM64_REG_V27, - UC_ARM64_REG_V28, - UC_ARM64_REG_V29, - UC_ARM64_REG_V30, - UC_ARM64_REG_V31, - - //> pseudo registers - UC_ARM64_REG_PC, // program counter register - - UC_ARM64_REG_CPACR_EL1, - - //> thread registers - UC_ARM64_REG_TPIDR_EL0, - UC_ARM64_REG_TPIDRRO_EL0, - UC_ARM64_REG_TPIDR_EL1, - - UC_ARM64_REG_ENDING, // <-- mark the end of the list of registers - - //> alias registers - - UC_ARM64_REG_IP0 = UC_ARM64_REG_X16, - UC_ARM64_REG_IP1 = UC_ARM64_REG_X17, - UC_ARM64_REG_FP = UC_ARM64_REG_X29, - UC_ARM64_REG_LR = UC_ARM64_REG_X30, -} uc_arm64_reg; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/app/libraries/unicorn/include/unicorn/platform.h b/app/libraries/unicorn/include/unicorn/platform.h deleted file mode 100644 index fcd2c84a..00000000 --- a/app/libraries/unicorn/include/unicorn/platform.h +++ /dev/null @@ -1,219 +0,0 @@ -/* This file is released under LGPL2. - See COPYING.LGPL2 in root directory for more details -*/ - -/* - This file is to support header files that are missing in MSVC and - other non-standard compilers. -*/ -#ifndef UNICORN_PLATFORM_H -#define UNICORN_PLATFORM_H - -/* -These are the various MSVC versions as given by _MSC_VER: -MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) -MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) -MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) -MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) -MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) -MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) -MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003) -MSVC++ 7.0 _MSC_VER == 1300 -MSVC++ 6.0 _MSC_VER == 1200 -MSVC++ 5.0 _MSC_VER == 1100 -*/ -#define MSC_VER_VS2003 1310 -#define MSC_VER_VS2005 1400 -#define MSC_VER_VS2008 1500 -#define MSC_VER_VS2010 1600 -#define MSC_VER_VS2012 1700 -#define MSC_VER_VS2013 1800 -#define MSC_VER_VS2015 1900 - -// handle stdbool.h compatibility -#if !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)) -// MSVC - -// stdbool.h -#if (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE) -// this system does not have stdbool.h -#ifndef __cplusplus -typedef unsigned char bool; -#define false 0 -#define true 1 -#endif // __cplusplus - -#else -// VisualStudio 2013+ -> C99 is supported -#include -#endif // (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE) - -#else -// not MSVC -> C99 is supported -#include -#endif // !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)) - -#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE) -// this system does not have stdint.h -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef signed long long int64_t; -typedef unsigned long long uint64_t; - -#ifndef _INTPTR_T_DEFINED - #define _INTPTR_T_DEFINED - #ifdef _WIN64 -typedef long long intptr_t; - #else /* _WIN64 */ -typedef _W64 int intptr_t; - #endif /* _WIN64 */ -#endif /* _INTPTR_T_DEFINED */ - -#ifndef _UINTPTR_T_DEFINED - #define _UINTPTR_T_DEFINED - #ifdef _WIN64 -typedef unsigned long long uintptr_t; - #else /* _WIN64 */ -typedef _W64 unsigned int uintptr_t; - #endif /* _WIN64 */ -#endif /* _UINTPTR_T_DEFINED */ - -#define INT8_MIN (-127i8 - 1) -#define INT16_MIN (-32767i16 - 1) -#define INT32_MIN (-2147483647i32 - 1) -#define INT64_MIN (-9223372036854775807i64 - 1) -#define INT8_MAX 127i8 -#define INT16_MAX 32767i16 -#define INT32_MAX 2147483647i32 -#define INT64_MAX 9223372036854775807i64 -#define UINT8_MAX 0xffui8 -#define UINT16_MAX 0xffffui16 -#define UINT32_MAX 0xffffffffui32 -#define UINT64_MAX 0xffffffffffffffffui64 -#else // this system has stdint.h -#include -#endif // (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE) - -// handle inttypes.h compatibility -#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013)) || defined(_KERNEL_MODE) -// this system does not have inttypes.h - -#define __PRI_8_LENGTH_MODIFIER__ "hh" -#define __PRI_64_LENGTH_MODIFIER__ "ll" - -#define PRId8 __PRI_8_LENGTH_MODIFIER__ "d" -#define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i" -#define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o" -#define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u" -#define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x" -#define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X" - -#define PRId16 "hd" -#define PRIi16 "hi" -#define PRIo16 "ho" -#define PRIu16 "hu" -#define PRIx16 "hx" -#define PRIX16 "hX" - -#if defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012) -#define PRId32 "ld" -#define PRIi32 "li" -#define PRIo32 "lo" -#define PRIu32 "lu" -#define PRIx32 "lx" -#define PRIX32 "lX" -#else // OSX -#define PRId32 "d" -#define PRIi32 "i" -#define PRIo32 "o" -#define PRIu32 "u" -#define PRIx32 "x" -#define PRIX32 "X" -#endif // defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012) - -#if defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012) -// redefine functions from inttypes.h used in cstool -#define strtoull _strtoui64 -#endif - -#define PRId64 __PRI_64_LENGTH_MODIFIER__ "d" -#define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i" -#define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o" -#define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u" -#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x" -#define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X" - -#else -// this system has inttypes.h by default -#include -#endif // #if defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE) - -// sys/time.h compatibility -#if defined(_MSC_VER) -#include -#include -#include - -static int gettimeofday(struct timeval* t, void* timezone) -{ - struct _timeb timebuffer; - _ftime( &timebuffer ); - t->tv_sec = (long)timebuffer.time; - t->tv_usec = 1000*timebuffer.millitm; - return 0; -} -#else -#include -#endif - -// unistd.h compatibility -#if defined(_MSC_VER) - -static int usleep(uint32_t usec) -{ - HANDLE timer; - LARGE_INTEGER due; - - timer = CreateWaitableTimer(NULL, TRUE, NULL); - if (!timer) - return -1; - - due.QuadPart = (-((int64_t) usec)) * 10LL; - if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0)) { - CloseHandle(timer); - return -1; - } - WaitForSingleObject(timer, INFINITE); - CloseHandle(timer); - - return 0; -} - -#else -#include -#endif - -// misc support -#if defined(_MSC_VER) -#ifdef _WIN64 -typedef signed __int64 ssize_t; -#else -typedef _W64 signed int ssize_t; -#endif - -#define va_copy(d,s) ((d) = (s)) -#define strcasecmp _stricmp -#if (_MSC_VER < MSC_VER_VS2015) -#define snprintf _snprintf -#endif -#if (_MSC_VER <= MSC_VER_VS2013) -#define strtoll _strtoi64 -#endif -#endif - - -#endif // UNICORN_PLATFORM_H diff --git a/app/libraries/unicorn/include/unicorn/unicorn.h b/app/libraries/unicorn/include/unicorn/unicorn.h deleted file mode 100644 index a53cce0d..00000000 --- a/app/libraries/unicorn/include/unicorn/unicorn.h +++ /dev/null @@ -1,725 +0,0 @@ -/* Unicorn Emulator Engine */ -/* By Nguyen Anh Quynh , 2015-2017 */ -/* This file is released under LGPL2. - See COPYING.LGPL2 in root directory for more details -*/ - -#ifndef UNICORN_ENGINE_H -#define UNICORN_ENGINE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "platform.h" -#include - -#if defined(UNICORN_HAS_OSXKERNEL) -#include -#else -#include -#include -#endif - -struct uc_struct; -typedef struct uc_struct uc_engine; - -typedef size_t uc_hook; - -#include "arm64.h" - -#ifdef __GNUC__ -#define DEFAULT_VISIBILITY __attribute__((visibility("default"))) -#else -#define DEFAULT_VISIBILITY -#endif - -#ifdef _MSC_VER -#pragma warning(disable:4201) -#pragma warning(disable:4100) -#ifdef UNICORN_SHARED -#define UNICORN_EXPORT __declspec(dllexport) -#else // defined(UNICORN_STATIC) -#define UNICORN_EXPORT -#endif -#else -#ifdef __GNUC__ -#define UNICORN_EXPORT __attribute__((visibility("default"))) -#else -#define UNICORN_EXPORT -#endif -#endif - -#ifdef __GNUC__ -#define UNICORN_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) -#define UNICORN_DEPRECATED __declspec(deprecated) -#else -#pragma message("WARNING: You need to implement UNICORN_DEPRECATED for this compiler") -#define UNICORN_DEPRECATED -#endif - -// Unicorn API version -#define UC_API_MAJOR 1 -#define UC_API_MINOR 0 - -// Unicorn package version -#define UC_VERSION_MAJOR UC_API_MAJOR -#define UC_VERSION_MINOR UC_API_MINOR -#define UC_VERSION_EXTRA 2 - - -/* - Macro to create combined version which can be compared to - result of uc_version() API. -*/ -#define UC_MAKE_VERSION(major, minor) ((major << 8) + minor) - -// Scales to calculate timeout on microsecond unit -// 1 second = 1000,000 microseconds -#define UC_SECOND_SCALE 1000000 -// 1 milisecond = 1000 nanoseconds -#define UC_MILISECOND_SCALE 1000 - -// Architecture type -typedef enum uc_arch { - UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2) - UC_ARCH_ARM64, // ARM-64, also called AArch64 - UC_ARCH_MIPS, // Mips architecture - UC_ARCH_X86, // X86 architecture (including x86 & x86-64) - UC_ARCH_PPC, // PowerPC architecture (currently unsupported) - UC_ARCH_SPARC, // Sparc architecture - UC_ARCH_M68K, // M68K architecture - UC_ARCH_MAX, -} uc_arch; - -// Mode type -typedef enum uc_mode { - UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) - UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode - // arm / arm64 - UC_MODE_ARM = 0, // ARM mode - UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2) - UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported) - UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported) - // mips - UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported) - UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported) - UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported) - UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA - UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA - // x86 / x64 - UC_MODE_16 = 1 << 1, // 16-bit mode - UC_MODE_32 = 1 << 2, // 32-bit mode - UC_MODE_64 = 1 << 3, // 64-bit mode - // ppc - UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported) - UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported) - UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported) - // sparc - UC_MODE_SPARC32 = 1 << 2, // 32-bit mode - UC_MODE_SPARC64 = 1 << 3, // 64-bit mode - UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported) - // m68k -} uc_mode; - -// All type of errors encountered by Unicorn API. -// These are values returned by uc_errno() -typedef enum uc_err { - UC_ERR_OK = 0, // No error: everything was fine - UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate() - UC_ERR_ARCH, // Unsupported architecture: uc_open() - UC_ERR_HANDLE, // Invalid handle - UC_ERR_MODE, // Invalid/unsupported mode: uc_open() - UC_ERR_VERSION, // Unsupported version (bindings) - UC_ERR_READ_UNMAPPED, // Quit emulation due to READ on unmapped memory: uc_emu_start() - UC_ERR_WRITE_UNMAPPED, // Quit emulation due to WRITE on unmapped memory: uc_emu_start() - UC_ERR_FETCH_UNMAPPED, // Quit emulation due to FETCH on unmapped memory: uc_emu_start() - UC_ERR_HOOK, // Invalid hook type: uc_hook_add() - UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start() - UC_ERR_MAP, // Invalid memory mapping: uc_mem_map() - UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start() - UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start() - UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start() - UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API) - UC_ERR_READ_UNALIGNED, // Unaligned read - UC_ERR_WRITE_UNALIGNED, // Unaligned write - UC_ERR_FETCH_UNALIGNED, // Unaligned fetch - UC_ERR_HOOK_EXIST, // hook for this event already existed - UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start() - UC_ERR_EXCEPTION // Unhandled CPU exception -} uc_err; - - -/* - Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK) - - @address: address where the code is being executed - @size: size of machine instruction(s) being executed, or 0 when size is unknown - @user_data: user data passed to tracing APIs. -*/ -typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data); - -/* - Callback function for tracing interrupts (for uc_hook_intr()) - - @intno: interrupt number - @user_data: user data passed to tracing APIs. -*/ -typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data); - -/* - Callback function for tracing IN instruction of X86 - - @port: port number - @size: data size (1/2/4) to be read from this port - @user_data: user data passed to tracing APIs. -*/ -typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void *user_data); - -/* - Callback function for OUT instruction of X86 - - @port: port number - @size: data size (1/2/4) to be written to this port - @value: data value to be written to this port -*/ -typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data); - -// All type of memory accesses for UC_HOOK_MEM_* -typedef enum uc_mem_type { - UC_MEM_READ = 16, // Memory is read from - UC_MEM_WRITE, // Memory is written to - UC_MEM_FETCH, // Memory is fetched - UC_MEM_READ_UNMAPPED, // Unmapped memory is read from - UC_MEM_WRITE_UNMAPPED, // Unmapped memory is written to - UC_MEM_FETCH_UNMAPPED, // Unmapped memory is fetched - UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory - UC_MEM_READ_PROT, // Read from read protected, but mapped, memory - UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory - UC_MEM_READ_AFTER, // Memory is read from (successful access) -} uc_mem_type; - -// All type of hooks for uc_hook_add() API. -typedef enum uc_hook_type { - // Hook all interrupt/syscall events - UC_HOOK_INTR = 1 << 0, - // Hook a particular instruction - only a very small subset of instructions supported here - UC_HOOK_INSN = 1 << 1, - // Hook a range of code - UC_HOOK_CODE = 1 << 2, - // Hook basic blocks - UC_HOOK_BLOCK = 1 << 3, - // Hook for memory read on unmapped memory - UC_HOOK_MEM_READ_UNMAPPED = 1 << 4, - // Hook for invalid memory write events - UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5, - // Hook for invalid memory fetch for execution events - UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6, - // Hook for memory read on read-protected memory - UC_HOOK_MEM_READ_PROT = 1 << 7, - // Hook for memory write on write-protected memory - UC_HOOK_MEM_WRITE_PROT = 1 << 8, - // Hook for memory fetch on non-executable memory - UC_HOOK_MEM_FETCH_PROT = 1 << 9, - // Hook memory read events. - UC_HOOK_MEM_READ = 1 << 10, - // Hook memory write events. - UC_HOOK_MEM_WRITE = 1 << 11, - // Hook memory fetch for execution events - UC_HOOK_MEM_FETCH = 1 << 12, - // Hook memory read events, but only successful access. - // The callback will be triggered after successful read. - UC_HOOK_MEM_READ_AFTER = 1 << 13, -} uc_hook_type; - -// Hook type for all events of unmapped memory access -#define UC_HOOK_MEM_UNMAPPED (UC_HOOK_MEM_READ_UNMAPPED + UC_HOOK_MEM_WRITE_UNMAPPED + UC_HOOK_MEM_FETCH_UNMAPPED) -// Hook type for all events of illegal protected memory access -#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT) -// Hook type for all events of illegal read memory access -#define UC_HOOK_MEM_READ_INVALID (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_UNMAPPED) -// Hook type for all events of illegal write memory access -#define UC_HOOK_MEM_WRITE_INVALID (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_UNMAPPED) -// Hook type for all events of illegal fetch memory access -#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED) -// Hook type for all events of illegal memory access -#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT) -// Hook type for all events of valid memory access -// NOTE: UC_HOOK_MEM_READ is triggered before UC_HOOK_MEM_READ_PROT and UC_HOOK_MEM_READ_UNMAPPED, so -// this hook may technically trigger on some invalid reads. -#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH) - -/* - Callback function for hooking memory (READ, WRITE & FETCH) - - @type: this memory is being READ, or WRITE - @address: address where the code is being executed - @size: size of data being read or written - @value: value of data being written to memory, or irrelevant if type = READ. - @user_data: user data passed to tracing APIs -*/ -typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type, - uint64_t address, int size, int64_t value, void *user_data); - -/* - Callback function for handling invalid memory access events (UNMAPPED and - PROT events) - - @type: this memory is being READ, or WRITE - @address: address where the code is being executed - @size: size of data being read or written - @value: value of data being written to memory, or irrelevant if type = READ. - @user_data: user data passed to tracing APIs - - @return: return true to continue, or false to stop program (due to invalid memory). - NOTE: returning true to continue execution will only work if if the accessed - memory is made accessible with the correct permissions during the hook. - - In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback, - the memory should be uc_mem_map()-ed with the correct permissions, and the - instruction will then read or write to the address as it was supposed to. - - In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be mapped - in as executable, in which case execution will resume from the fetched address. - The instruction pointer may be written to in order to change where execution resumes, - but the fetch must succeed if execution is to resume. -*/ -typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type, - uint64_t address, int size, int64_t value, void *user_data); - -/* - Memory region mapped by uc_mem_map() and uc_mem_map_ptr() - Retrieve the list of memory regions with uc_mem_regions() -*/ -typedef struct uc_mem_region { - uint64_t begin; // begin address of the region (inclusive) - uint64_t end; // end address of the region (inclusive) - uint32_t perms; // memory permissions of the region -} uc_mem_region; - -// All type of queries for uc_query() API. -typedef enum uc_query_type { - // Dynamically query current hardware mode. - UC_QUERY_MODE = 1, - UC_QUERY_PAGE_SIZE, - UC_QUERY_ARCH, -} uc_query_type; - -// Opaque storage for CPU context, used with uc_context_*() -struct uc_context; -typedef struct uc_context uc_context; - -/* - Return combined API version & major and minor version numbers. - - @major: major number of API version - @minor: minor number of API version - - @return hexical number as (major << 8 | minor), which encodes both - major & minor versions. - NOTE: This returned value can be compared with version number made - with macro UC_MAKE_VERSION - - For example, second API version would return 1 in @major, and 1 in @minor - The return value would be 0x0101 - - NOTE: if you only care about returned value, but not major and minor values, - set both @major & @minor arguments to NULL. -*/ -UNICORN_EXPORT -unsigned int uc_version(unsigned int *major, unsigned int *minor); - - -/* - Determine if the given architecture is supported by this library. - - @arch: architecture type (UC_ARCH_*) - - @return True if this library supports the given arch. -*/ -UNICORN_EXPORT -bool uc_arch_supported(uc_arch arch); - - -/* - Create new instance of unicorn engine. - - @arch: architecture type (UC_ARCH_*) - @mode: hardware mode. This is combined of UC_MODE_* - @uc: pointer to uc_engine, which will be updated at return time - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc); - -/* - Close a Unicorn engine instance. - NOTE: this must be called only when there is no longer any - usage of @uc. This API releases some of @uc's cached memory, thus - any use of the Unicorn API with @uc after it has been closed may - crash your application. After this, @uc is invalid, and is no - longer usable. - - @uc: pointer to a handle returned by uc_open() - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_close(uc_engine *uc); - -/* - Query internal status of engine. - - @uc: handle returned by uc_open() - @type: query type. See uc_query_type - - @result: save the internal status queried - - @return: error code of uc_err enum type (UC_ERR_*, see above) -*/ -UNICORN_EXPORT -uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result); - -/* - Report the last error number when some API function fail. - Like glibc's errno, uc_errno might not retain its old value once accessed. - - @uc: handle returned by uc_open() - - @return: error code of uc_err enum type (UC_ERR_*, see above) -*/ -UNICORN_EXPORT -uc_err uc_errno(uc_engine *uc); - -/* - Return a string describing given error code. - - @code: error code (see UC_ERR_* above) - - @return: returns a pointer to a string that describes the error code - passed in the argument @code - */ -UNICORN_EXPORT -const char *uc_strerror(uc_err code); - -/* - Write to register. - - @uc: handle returned by uc_open() - @regid: register ID that is to be modified. - @value: pointer to the value that will set to register @regid - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_reg_write(uc_engine *uc, int regid, const void *value); - -/* - Read register value. - - @uc: handle returned by uc_open() - @regid: register ID that is to be retrieved. - @value: pointer to a variable storing the register value. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_reg_read(uc_engine *uc, int regid, void *value); - -/* - Write multiple register values. - - @uc: handle returned by uc_open() - @rges: array of register IDs to store - @value: pointer to array of register values - @count: length of both *regs and *vals - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count); - -/* - Read multiple register values. - - @uc: handle returned by uc_open() - @rges: array of register IDs to retrieve - @value: pointer to array of values to hold registers - @count: length of both *regs and *vals - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count); - -/* - Write to a range of bytes in memory. - - @uc: handle returned by uc_open() - @address: starting memory address of bytes to set. - @bytes: pointer to a variable containing data to be written to memory. - @size: size of memory to write to. - - NOTE: @bytes must be big enough to contain @size bytes. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size); - -/* - Read a range of bytes in memory. - - @uc: handle returned by uc_open() - @address: starting memory address of bytes to get. - @bytes: pointer to a variable containing data copied from memory. - @size: size of memory to read. - - NOTE: @bytes must be big enough to contain @size bytes. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size); - -/* - Emulate machine code in a specific duration of time. - - @uc: handle returned by uc_open() - @begin: address where emulation starts - @until: address where emulation stops (i.e when this address is hit) - @timeout: duration to emulate the code (in microseconds). When this value is 0, - we will emulate the code in infinite time, until the code is finished. - @count: the number of instructions to be emulated. When this value is 0, - we will emulate all the code available, until the code is finished. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); - -/* - Stop emulation (which was started by uc_emu_start() API. - This is typically called from callback functions registered via tracing APIs. - - @uc: handle returned by uc_open() - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_emu_stop(uc_engine *uc); - -/* - Register callback for a hook event. - The callback will be run when the hook event is hit. - - @uc: handle returned by uc_open() - @hh: hook handle returned from this registration. To be used in uc_hook_del() API - @type: hook type - @callback: callback to be run when instruction is hit - @user_data: user-defined data. This will be passed to callback function in its - last argument @user_data - @begin: start address of the area where the callback is effect (inclusive) - @end: end address of the area where the callback is effect (inclusive) - NOTE 1: the callback is called only if related address is in range [@begin, @end] - NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered - @...: variable arguments (depending on @type) - NOTE: if @type = UC_HOOK_INSN, this is the instruction ID (ex: UC_X86_INS_OUT) - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, - void *user_data, uint64_t begin, uint64_t end, ...); - -/* - Unregister (remove) a hook callback. - This API removes the hook callback registered by uc_hook_add(). - NOTE: this should be called only when you no longer want to trace. - After this, @hh is invalid, and nolonger usable. - - @uc: handle returned by uc_open() - @hh: handle returned by uc_hook_add() - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_hook_del(uc_engine *uc, uc_hook hh); - -typedef enum uc_prot { - UC_PROT_NONE = 0, - UC_PROT_READ = 1, - UC_PROT_WRITE = 2, - UC_PROT_EXEC = 4, - UC_PROT_ALL = 7, -} uc_prot; - -/* - Map memory in for emulation. - This API adds a memory region that can be used by emulation. - - @uc: handle returned by uc_open() - @address: starting address of the new memory region to be mapped in. - This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. - @size: size of the new memory region to be mapped in. - This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. - @perms: Permissions for the newly mapped region. - This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, - or this will return with UC_ERR_ARG error. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); - -/* - Map existing host memory in for emulation. - This API adds a memory region that can be used by emulation. - - @uc: handle returned by uc_open() - @address: starting address of the new memory region to be mapped in. - This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. - @size: size of the new memory region to be mapped in. - This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. - @perms: Permissions for the newly mapped region. - This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, - or this will return with UC_ERR_ARG error. - @ptr: pointer to host memory backing the newly mapped memory. This host memory is - expected to be an equal or larger size than provided, and be mapped with at - least PROT_READ | PROT_WRITE. If it is not, the resulting behavior is undefined. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr); - -/* - Unmap a region of emulation memory. - This API deletes a memory mapping from the emulation memory space. - - @uc: handle returned by uc_open() - @address: starting address of the memory region to be unmapped. - This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. - @size: size of the memory region to be modified. - This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size); - -/* - Set memory permissions for emulation memory. - This API changes permissions on an existing memory region. - - @uc: handle returned by uc_open() - @address: starting address of the memory region to be modified. - This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. - @size: size of the memory region to be modified. - This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. - @perms: New permissions for the mapped region. - This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, - or this will return with UC_ERR_ARG error. - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); - -/* - Retrieve all memory regions mapped by uc_mem_map() and uc_mem_map_ptr() - This API allocates memory for @regions, and user must free this memory later - by free() to avoid leaking memory. - NOTE: memory regions may be splitted by uc_mem_unmap() - - @uc: handle returned by uc_open() - @regions: pointer to an array of uc_mem_region struct. This is allocated by - Unicorn, and must be freed by user later with uc_free() - @count: pointer to number of struct uc_mem_region contained in @regions - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count); - -/* - Allocate a region that can be used with uc_context_{save,restore} to perform - quick save/rollback of the CPU context, which includes registers and some - internal metadata. Contexts may not be shared across engine instances with - differing arches or modes. - - @uc: handle returned by uc_open() - @context: pointer to a uc_engine*. This will be updated with the pointer to - the new context on successful return of this function. - Later, this allocated memory must be freed with uc_free(). - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_context_alloc(uc_engine *uc, uc_context **context); - -/* - Free the memory allocated by uc_context_alloc & uc_mem_regions. - - @mem: memory allocated by uc_context_alloc (returned in *context), or - by uc_mem_regions (returned in *regions) - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_free(void *mem); - -/* - Save a copy of the internal CPU context. - This API should be used to efficiently make or update a saved copy of the - internal CPU state. - - @uc: handle returned by uc_open() - @context: handle returned by uc_context_alloc() - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_context_save(uc_engine *uc, uc_context *context); - -/* - Restore the current CPU context from a saved copy. - This API should be used to roll the CPU context back to a previous - state saved by uc_context_save(). - - @uc: handle returned by uc_open() - @buffer: handle returned by uc_context_alloc that has been used with uc_context_save - - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). -*/ -UNICORN_EXPORT -uc_err uc_context_restore(uc_engine *uc, uc_context *context); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/app/libraries/unicorn/libunicorn.a b/app/libraries/unicorn/libunicorn.a deleted file mode 100644 index 6f3c7da9..00000000 Binary files a/app/libraries/unicorn/libunicorn.a and /dev/null differ diff --git a/app/src/main/cpp/switch/constant.h b/app/src/main/cpp/switch/constant.h index 9e026f18..1f22490a 100644 --- a/app/src/main/cpp/switch/constant.h +++ b/app/src/main/cpp/switch/constant.h @@ -10,11 +10,63 @@ namespace lightSwitch { namespace constant { constexpr uint64_t base_addr = 0x80000000; constexpr uint64_t stack_addr = 0x3000000; - constexpr size_t stack_size = 0x1000000; + constexpr size_t stack_size = 280; //0x1000000 constexpr uint64_t tls_addr = 0x2000000; constexpr size_t tls_size = 0x1000; constexpr uint32_t nro_magic = 0x304F524E; // NRO0 in reverse constexpr uint_t svc_unimpl = 0x177202; // "Unimplemented behaviour" - constexpr uint32_t base_handle_index = 0xd001; + constexpr uint32_t base_handle_index = 0xD001; + constexpr uint16_t svc_last = 0x7F; + constexpr uint8_t num_regs = 31; + constexpr uint32_t tpidrro_el0 = 0x5E83; // ID of tpidrro_el0 in MRS + }; + + namespace instr { + // https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction + // For some reason if value is set to uint16_t it isn't read correctly ? + struct brk { + brk(uint16_t val) { + start = 0x0; // First 5 bits of an BRK instruction are 0 + value = val; + end = 0x6A1; // Last 11 bits of an BRK instruction stored as uint16_t + } + + bool verify() { + return (start == 0x0 && end == 0x6A1); + } + + uint8_t start:5; + uint32_t value:16; + uint16_t end:11; + }; + + // https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/svc-supervisor-call + struct svc { + bool verify() { + return (start == 0x1 && end == 0x6A0); + } + + uint8_t start:5; + uint32_t value:16; + uint16_t end:11; + }; + + // https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register + struct mrs { + bool verify() { + return (end == 0xD53); + } + + uint8_t Xt:5; + uint32_t Sreg:15; + uint16_t end:12; + }; + }; + + enum xreg { + x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30 + }; + enum wreg { + w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24, w25, w26, w27, w28, w29, w30 }; } \ No newline at end of file diff --git a/app/src/main/cpp/switch/device.h b/app/src/main/cpp/switch/device.h index b95bbffc..40ba0ccb 100644 --- a/app/src/main/cpp/switch/device.h +++ b/app/src/main/cpp/switch/device.h @@ -15,7 +15,7 @@ namespace lightSwitch { {"NRO", 1} }; public: - device(std::shared_ptr &logger, std::shared_ptr &settings) : cpu(new hw::Cpu()), memory(new hw::Memory(cpu->GetEngine())), state{cpu, memory, settings, logger}, os({cpu, memory, settings, logger}) {}; + device(std::shared_ptr &logger, std::shared_ptr &settings) : cpu(new hw::Cpu()), memory(new hw::Memory()), state{cpu, memory, settings, logger}, os({cpu, memory, settings, logger}) {}; void run(std::string rom_file) { try { @@ -27,7 +27,7 @@ namespace lightSwitch { default: break; } - cpu->Execute(constant::base_addr); + cpu->Execute(hw::Memory::text, memory, os.SvcHandler, &state); } catch (std::out_of_range &e) { throw exception("The ROM extension wasn't recognized."); } diff --git a/app/src/main/cpp/switch/hw/cpu.cpp b/app/src/main/cpp/switch/hw/cpu.cpp index b44a47fe..2fef2d5b 100644 --- a/app/src/main/cpp/switch/hw/cpu.cpp +++ b/app/src/main/cpp/switch/hw/cpu.cpp @@ -1,46 +1,125 @@ #include "cpu.h" #include "../constant.h" - namespace lightSwitch::hw { - Cpu::Cpu() { - err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc); - if (err) - throw std::runtime_error("An error occurred while running 'uc_open': " + std::string(uc_strerror(err))); - } - Cpu::~Cpu() { - uc_close(uc); + if (child) kill(child, SIGKILL); } - void Cpu::Execute(uint64_t address) { - // Set Registers - SetRegister(UC_ARM64_REG_SP, constant::stack_addr + 0x100000); // Stack Pointer (For some reason programs move the stack pointer backwards so 0x100000 is added) - SetRegister(UC_ARM64_REG_TPIDRRO_EL0, constant::tls_addr); // User Read-Only Thread ID Register - err = uc_emu_start(uc, address, std::numeric_limits::max(), 0, 0); - if (err) - throw std::runtime_error("An error occurred while running 'uc_emu_start': " + std::string(uc_strerror(err))); + long *Cpu::ReadMemory(uint64_t address) { // Return a single word (32-bit) + status = ptrace(PTRACE_PEEKDATA, child, address, NULL); + if (status == -1) throw std::runtime_error("Cannot read memory"); + return &status; } - void Cpu::StopExecution() { - uc_emu_stop(uc); + void Cpu::WriteMemory(uint64_t address) { // Write a single word (32-bit) + status = ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, &iov); + if (status == -1) throw std::runtime_error("Cannot write memory"); } - uint64_t Cpu::GetRegister(uint32_t reg_id) { - uint64_t registerValue; - err = uc_reg_read(uc, reg_id, ®isterValue); - if (err) - throw std::runtime_error("An error occurred while running 'uc_reg_read': " + std::string(uc_strerror(err))); - return registerValue; + void Cpu::ReadRegisters() { // Read all registers into 'regs' + iov = {®s, sizeof(regs)}; + status = ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, &iov); + if (status == -1) throw std::runtime_error("Cannot read registers"); } - void Cpu::SetRegister(uint32_t regid, uint64_t value) { - err = uc_reg_write(uc, regid, &value); - if (err) - throw std::runtime_error("An error occurred while running 'uc_reg_write': " + std::string(uc_strerror(err))); + void Cpu::WriteRegisters() { // Write all registers from 'regs' + iov = {®s, sizeof(regs)}; + status = ptrace(PTRACE_SETREGSET, child, NT_PRSTATUS, &iov); + if (status == -1) throw std::runtime_error("Cannot write registers"); } - uc_engine *Cpu::GetEngine() { - return uc; + void Cpu::ResumeProcess() { // Resumes a process stopped due to a signal + status = ptrace(PTRACE_CONT, child, NULL, NULL); + if (status == -1) throw std::runtime_error("Cannot resume process"); + } + + void bin(unsigned n) { + unsigned i; + std::string s; + for (i = 1 << 31; i > 0; i = i / 2) + (n & i) ? s += "1" : s += "0"; + s = s.substr(16); + syslog(LOG_WARNING, "%s", s.c_str()); + } + + void Cpu::WriteBreakpoint(uint64_t &address_, uint64_t &size) { + auto address = (uint32_t *) address_; + for (uint64_t iter = 0; iter < size; iter++) { + auto instr_svc = reinterpret_cast(address + iter); + auto instr_mrs = reinterpret_cast(address + iter); + if (instr_svc->verify()) { + // syslog(LOG_WARNING, "Found SVC call: 0x%X, At location 0x%X", instr_svc->value, ((uint64_t)address)+iter); + instr::brk brk((uint16_t) instr_svc->value); + address[iter] = *(uint32_t *) (&brk); + } else if (instr_mrs->verify() && instr_mrs->Sreg == constant::tpidrro_el0) { + // syslog(LOG_WARNING, "Found MRS call: 0x%X, At location 0x%X", instr_mrs->Xt, ((uint64_t)address)+iter); + instr::brk brk((uint16_t) (constant::svc_last + 1 + instr_mrs->Xt)); + address[iter] = *(uint32_t *) (&brk); + } + } + } + + void Cpu::Execute(Memory::Region region, std::shared_ptr memory, std::function svc_handler, void *device) { + tls = memory->region_map.at(hw::Memory::tls).address; + hw::Memory::RegionData rom = memory->region_map.at(hw::Memory::text); + WriteBreakpoint(rom.address, rom.size); + child = ExecuteChild(rom.address); + int stat = 0; + while (waitpid(child, &stat, 0)) { + if (WIFSTOPPED(stat)) { + ReadRegisters(); + //syslog(LOG_INFO, "PC is at 0x%X", regs.pc); + if (!regs.pc || regs.pc == 0xBADC0DE) break; + // We store the instruction value as the immediate value. 0x0 to 0x7F are SVC, 0x80 to 0x9E is MRS for TPIDRRO_EL0. + auto instr = reinterpret_cast(ReadMemory(regs.pc)); + if (instr->verify()) { + if (instr->value <= constant::svc_last) { + svc_handler((uint16_t) instr->value, device); + syslog(LOG_ERR, "SVC has been called 0x%X", instr->value); + if (stop) break; + } else if (instr->value > constant::svc_last && instr->value <= constant::svc_last + constant::num_regs) { + // Catch MRS that reads the value of TPIDRRO_EL0 (TLS) + // https://switchbrew.org/wiki/Thread_Local_Storage + SetRegister(xreg(instr->value - (constant::svc_last + 1)), tls); + syslog(LOG_ERR, "MRS has been called 0x%X", instr->value - (constant::svc_last + 1)); + } else syslog(LOG_ERR, "Received unhandled BRK 0x%X", instr->value); + } + regs.pc += 4; // Increment program counter by a single instruction (32 bits) + WriteRegisters(); + } else if (WIFEXITED(stat)) + break; + ResumeProcess(); + } + kill(child, SIGABRT); + child = 0; + stop = false; + } + + pid_t Cpu::ExecuteChild(uint64_t address) { + pid_t pid = fork(); + if (!pid) { + ptrace(PTRACE_TRACEME, 0, NULL, NULL); + asm volatile("BR %0"::"r"(address)); + } + return pid; + } + + void Cpu::StopExecution() { stop = true; } + + uint64_t Cpu::GetRegister(xreg reg_id) { + return regs.regs[reg_id]; + } + + void Cpu::SetRegister(xreg reg_id, uint64_t value) { + regs.regs[reg_id] = value; + } + + uint64_t Cpu::GetRegister(wreg reg_id) { + return ((uint32_t *) regs.regs)[wreg_lut[reg_id]]; + } + + void Cpu::SetRegister(wreg reg_id, uint32_t value) { + ((uint32_t *) regs.regs)[wreg_lut[reg_id]] = value; } } \ No newline at end of file diff --git a/app/src/main/cpp/switch/hw/cpu.h b/app/src/main/cpp/switch/hw/cpu.h index bc9c343e..90a658dd 100644 --- a/app/src/main/cpp/switch/hw/cpu.h +++ b/app/src/main/cpp/switch/hw/cpu.h @@ -1,29 +1,54 @@ #pragma once #include -#include +#include +#include +#include +#include +#include +#include +#include +#include "memory.h" namespace lightSwitch::hw { class Cpu { private: - uc_engine *uc; - uc_err err; + bool stop = false; + long status = 0; + pid_t child; + iovec iov; + user_pt_regs regs; + uint64_t tls; + + static pid_t ExecuteChild(uint64_t address); + + void ReadRegisters(); + + void WriteRegisters(); + + long *ReadMemory(uint64_t address); + + void WriteMemory(uint64_t address); + + void ResumeProcess(); + + void WriteBreakpoint(uint64_t &address, uint64_t &size); + + uint8_t wreg_lut[31] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61}; public: - Cpu(); - ~Cpu(); - void SetHook(void *HookInterrupt); - - void Execute(uint64_t address); + void Execute(Memory::Region region, std::shared_ptr memory, std::function svc_handler, void *device); void StopExecution(); - uint64_t GetRegister(uint32_t regid); + uint64_t GetRegister(xreg reg_id); - void SetRegister(uint32_t regid, uint64_t value); + void SetRegister(xreg reg_id, uint64_t value); - uc_engine *GetEngine(); + uint64_t GetRegister(wreg reg_id); + + void SetRegister(wreg reg_id, uint32_t value); }; } diff --git a/app/src/main/cpp/switch/hw/memory.cpp b/app/src/main/cpp/switch/hw/memory.cpp index a32c32d0..ba3e11b8 100644 --- a/app/src/main/cpp/switch/hw/memory.cpp +++ b/app/src/main/cpp/switch/hw/memory.cpp @@ -6,21 +6,18 @@ namespace lightSwitch::hw { // TODO: Boundary checks - Memory::Memory(uc_engine *uc_) : uc(uc_) { + Memory::Memory() { // Map stack memory - Memory::Map(constant::stack_addr, constant::stack_size, stack); + // Memory::Map(constant::stack_addr, constant::stack_size, stack); // Map TLS memory Memory::Map(constant::tls_addr, constant::tls_size, tls); } void Memory::Map(uint64_t address, size_t size, Region region) { region_map.insert(std::pair(region, {address, size})); - void *ptr = mmap((void *) address, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0); + void *ptr = mmap((void *) address, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON | MAP_FIXED, 0, 0); if (!ptr) throw exception("An occurred while mapping region"); - uc_err err = uc_mem_map_ptr(uc, address, size, UC_PROT_ALL, (void *) address); - if (err) - throw exception("Unicorn failed to map region: " + std::string(uc_strerror(err))); } void Memory::Write(void *data, uint64_t offset, size_t size) { diff --git a/app/src/main/cpp/switch/hw/memory.h b/app/src/main/cpp/switch/hw/memory.h index adf1d70a..6500528c 100644 --- a/app/src/main/cpp/switch/hw/memory.h +++ b/app/src/main/cpp/switch/hw/memory.h @@ -1,13 +1,10 @@ #pragma once #include -#include #include namespace lightSwitch::hw { class Memory { - private: - uc_engine *uc; public: enum Region { stack, tls, text, rodata, data, bss @@ -18,7 +15,7 @@ namespace lightSwitch::hw { }; std::map region_map; - Memory(uc_engine *uc_); + Memory(); void Map(uint64_t address, size_t size, Region region); diff --git a/app/src/main/cpp/switch/os/ipc.h b/app/src/main/cpp/switch/os/ipc.h index 7df3002a..90d4c683 100644 --- a/app/src/main/cpp/switch/os/ipc.h +++ b/app/src/main/cpp/switch/os/ipc.h @@ -22,7 +22,7 @@ namespace lightSwitch::os::ipc { bool handle_desc : 1; } *req_info; - IpcRequest(uint8_t *tlsPtr, device_state& state); + IpcRequest(uint8_t *tlsPtr, device_state &state); template T GetValue(); diff --git a/app/src/main/cpp/switch/os/os.cpp b/app/src/main/cpp/switch/os/os.cpp index 9a7a5c23..3a189d1f 100644 --- a/app/src/main/cpp/switch/os/os.cpp +++ b/app/src/main/cpp/switch/os/os.cpp @@ -1,49 +1,18 @@ -#include #include "os.h" namespace lightSwitch::os { - OS::OS(device_state state_) : state(std::move(state_)) { - uc_err err = uc_hook_add(state.cpu->GetEngine(), &hook, UC_HOOK_INTR, - (void *) HookInterrupt, &state, 1, 0); - if (err) - throw std::runtime_error("An error occurred while running 'uc_hook_add': " + - std::string(uc_strerror(err))); - } + OS::OS(device_state state_) : state(std::move(state_)) {} - OS::~OS() { - uc_hook_del(state.cpu->GetEngine(), hook); - } - - void OS::HookInterrupt(uc_engine *uc, uint32_t int_no, void *user_data) { - device_state state = *((device_state *) user_data); - try { - if (int_no == 2) { - uint32_t instr{}; - uc_err err = uc_mem_read(uc, state.cpu->GetRegister(UC_ARM64_REG_PC) - 4, &instr, 4); - if (err) - throw exception("An error occurred while running 'uc_mem_read': " + std::string(uc_strerror(err))); - uint32_t svcId = instr >> 5U & 0xFF; - SvcHandler(svcId, state); - } else { - state.logger->write(Logger::ERROR, "An unhandled interrupt has occurred: {}", int_no); - state.cpu->StopExecution(); - } - } catch (exception &e) { - state.logger->write(Logger::WARN, "An exception occurred during an interrupt: {}", e.what()); - } catch (...) { - state.logger->write(Logger::WARN, "An unknown exception has occurred."); - } - } - - void OS::SvcHandler(uint32_t svc, device_state &state) { + void OS::SvcHandler(uint16_t svc, void *vstate) { + device_state state = *((device_state *) vstate); if (svc::svcTable[svc]) (*svc::svcTable[svc])(state); else state.logger->write(Logger::WARN, "Unimplemented SVC 0x{0:x}", svc); } - void OS::SvcHandler(uint32_t svc) { - SvcHandler(svc, state); + void OS::HandleSvc(uint16_t svc) { + SvcHandler(svc, &state); } } \ No newline at end of file diff --git a/app/src/main/cpp/switch/os/os.h b/app/src/main/cpp/switch/os/os.h index 7d146ed7..189c32e1 100644 --- a/app/src/main/cpp/switch/os/os.h +++ b/app/src/main/cpp/switch/os/os.h @@ -11,16 +11,11 @@ namespace lightSwitch::os { class OS { private: device_state state; - uc_hook hook{}; public: OS(device_state state_); - ~OS(); + static void SvcHandler(uint16_t svc, void *vstate); - static void HookInterrupt(uc_engine *uc, uint32_t int_no, void *user_data); - - static void SvcHandler(uint32_t svc, device_state &state); - - void SvcHandler(uint32_t svc); + void HandleSvc(uint16_t svc); }; } \ No newline at end of file diff --git a/app/src/main/cpp/switch/os/svc.cpp b/app/src/main/cpp/switch/os/svc.cpp index ba603994..248dfe27 100644 --- a/app/src/main/cpp/switch/os/svc.cpp +++ b/app/src/main/cpp/switch/os/svc.cpp @@ -2,56 +2,55 @@ #include #include #include -#include #include "svc.h" namespace lightSwitch::os::svc { void ConnectToNamedPort(device_state &state) { char port[constant::port_size]{0}; - state.mem->Read(port, state.cpu->GetRegister(UC_ARM64_REG_X1), constant::port_size); + state.mem->Read(port, state.cpu->GetRegister(xreg::x1), constant::port_size); if (std::strcmp(port, "sm:") == 0) - state.cpu->SetRegister(UC_ARM64_REG_W1, constant::sm_handle); + state.cpu->SetRegister(wreg::w1, constant::sm_handle); else { state.logger->write(Logger::ERROR, "svcConnectToNamedPort tried connecting to invalid port \"{0}\"", port); state.cpu->StopExecution(); } - state.cpu->SetRegister(UC_ARM64_REG_W0, 0); + state.cpu->SetRegister(wreg::w0, 0); } void SendSyncRequest(device_state &state) { - state.logger->write(Logger::DEBUG, "svcSendSyncRequest called for handle 0x{0:x}.", state.cpu->GetRegister(UC_ARM64_REG_X0)); + state.logger->write(Logger::DEBUG, "svcSendSyncRequest called for handle 0x{0:x}.", state.cpu->GetRegister(xreg::x0)); uint8_t tls[constant::tls_ipc_size]; state.mem->Read(&tls, constant::tls_addr, constant::tls_ipc_size); ipc::IpcRequest request(tls, state); - state.cpu->SetRegister(UC_ARM64_REG_W0, 0); + state.cpu->SetRegister(wreg::w0, 0); } void OutputDebugString(device_state &state) { - std::string debug(state.cpu->GetRegister(UC_ARM64_REG_X1), '\0'); - state.mem->Read((void *) debug.data(), state.cpu->GetRegister(UC_ARM64_REG_X0), state.cpu->GetRegister(UC_ARM64_REG_X1)); + std::string debug(state.cpu->GetRegister(xreg::x1), '\0'); + state.mem->Read((void *) debug.data(), state.cpu->GetRegister(xreg::x0), state.cpu->GetRegister(xreg::x1)); state.logger->write(Logger::INFO, "ROM Output: {0}", debug.c_str()); - state.cpu->SetRegister(UC_ARM64_REG_W0, 0); + state.cpu->SetRegister(wreg::w0, 0); } void GetInfo(device_state &state) { - switch (state.cpu->GetRegister(UC_ARM64_REG_X1)) { + switch (state.cpu->GetRegister(xreg::x1)) { case constant::infoState::AllowedCpuIdBitmask: case constant::infoState::AllowedThreadPriorityMask: case constant::infoState::IsCurrentProcessBeingDebugged: - state.cpu->SetRegister(UC_ARM64_REG_X1, 0); + state.cpu->SetRegister(xreg::x1, 0); break; case constant::infoState::AddressSpaceBaseAddr: - state.cpu->SetRegister(UC_ARM64_REG_X1, constant::base_addr); + state.cpu->SetRegister(xreg::x1, constant::base_addr); break; case constant::infoState::TitleId: - state.cpu->SetRegister(UC_ARM64_REG_X1, 0); // TODO: Complete this + state.cpu->SetRegister(xreg::x1, 0); // TODO: Complete this break; default: - state.logger->write(Logger::WARN, "Unimplemented GetInfo call. ID1: {0}, ID2: {1}", state.cpu->GetRegister(UC_ARM64_REG_X1), state.cpu->GetRegister(UC_ARM64_REG_X3)); - state.cpu->SetRegister(UC_ARM64_REG_X1, constant::svc_unimpl); + state.logger->write(Logger::WARN, "Unimplemented GetInfo call. ID1: {0}, ID2: {1}", state.cpu->GetRegister(xreg::x1), state.cpu->GetRegister(xreg::x3)); + state.cpu->SetRegister(xreg::x1, constant::svc_unimpl); return; } - state.cpu->SetRegister(UC_ARM64_REG_W0, 0); + state.cpu->SetRegister(wreg::w0, 0); } void ExitProcess(device_state &state) {