diff --git a/.idea/vcs.xml b/.idea/vcs.xml index c8397c9..aa851fd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 177d9d0..c633c66 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -23,8 +23,16 @@ android { versionName = "v15.2" externalNativeBuild { - ndk { - jobs = Runtime.getRuntime().availableProcessors() + cmake { + arguments += "-DANDROID_STL=none" + arguments += "-DCMAKE_BUILD_TYPE=MinSizeRel" + arguments += "-DPlugin.Android.BionicLinkerUtil=ON" + + cppFlags += "-std=c++20" + cppFlags += "-fno-exceptions" + cppFlags += "-fno-rtti" + cppFlags += "-fvisibility=hidden" + cppFlags += "-fvisibility-inlines-hidden" } } } @@ -33,7 +41,9 @@ android { release { isMinifyEnabled = true isShrinkResources = true - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" + ) } } @@ -43,8 +53,9 @@ android { } externalNativeBuild { - ndkBuild { - path = file("src/main/cpp/Android.mk") + cmake { + path = file("src/main/cpp/CMakeLists.txt") + version = "3.22.1" } } } @@ -71,8 +82,10 @@ tasks.register("copyFiles") { doLast { val moduleFolder = project.rootDir.resolve("module") - val dexFile = project.layout.buildDirectory.get().asFile.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex") - val soDir = project.layout.buildDirectory.get().asFile.resolve("intermediates/stripped_native_libs/release/out/lib") + val dexFile = + project.layout.buildDirectory.get().asFile.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex") + val soDir = + project.layout.buildDirectory.get().asFile.resolve("intermediates/stripped_native_libs/release/out/lib") dexFile.copyTo(moduleFolder.resolve("classes.dex"), overwrite = true) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 2f11af0..47abbdb 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,3 +1 @@ --keep class es.chiteroman.playintegrityfix.EntryPoint {public ;} --keep class es.chiteroman.playintegrityfix.CustomProvider --keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi \ No newline at end of file +-keep class es.chiteroman.playintegrityfix.EntryPoint {public ;} \ No newline at end of file diff --git a/app/src/main/cpp/Android.mk b/app/src/main/cpp/Android.mk deleted file mode 100644 index bd44239..0000000 --- a/app/src/main/cpp/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := dobby -LOCAL_SRC_FILES := $(LOCAL_PATH)/dobby/$(TARGET_ARCH_ABI)/libdobby.a -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/dobby -include $(PREBUILT_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_MODULE := zygisk -LOCAL_SRC_FILES := main.cpp -LOCAL_STATIC_LIBRARIES := libcxx dobby -LOCAL_LDLIBS := -llog -include $(BUILD_SHARED_LIBRARY) - -include $(LOCAL_PATH)/libcxx/Android.mk \ No newline at end of file diff --git a/app/src/main/cpp/Application.mk b/app/src/main/cpp/Application.mk deleted file mode 100644 index 6e01d55..0000000 --- a/app/src/main/cpp/Application.mk +++ /dev/null @@ -1,6 +0,0 @@ -APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 -APP_CFLAGS := -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -Oz -flto -APP_CPPFLAGS := -std=c++20 -fno-exceptions -fno-rtti -APP_LDFLAGS := -Oz -flto -Wl,--exclude-libs,ALL -Wl,--gc-sections -APP_STL := none -APP_PLATFORM := android-26 \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..e0525a2 --- /dev/null +++ b/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.22.1) + +project("playintegrityfix") + +include_directories(${CMAKE_SOURCE_DIR}/libcxx/include) + +link_libraries(${CMAKE_SOURCE_DIR}/libcxx/${CMAKE_ANDROID_ARCH_ABI}/libcxx.a) + +add_library(${CMAKE_PROJECT_NAME} SHARED + main.cpp) + +if (NOT TARGET dobby) + set(DOBBY_DIR ${CMAKE_SOURCE_DIR}/Dobby) + macro(SET_OPTION option value) + set(${option} ${value} CACHE INTERNAL "" FORCE) + endmacro() + SET_OPTION(DOBBY_DEBUG OFF) + SET_OPTION(DOBBY_GENERATE_SHARED OFF) + SET_OPTION(Plugin.Android.BionicLinkerUtil ON) + add_subdirectory(${DOBBY_DIR} dobby) + get_property(DOBBY_INCLUDE_DIRECTORIES + TARGET dobby + PROPERTY INCLUDE_DIRECTORIES) + include_directories( + . + ${DOBBY_INCLUDE_DIRECTORIES} + $ + ) +endif () + +target_link_libraries(${CMAKE_PROJECT_NAME} + log + dobby) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/.clang-format b/app/src/main/cpp/Dobby/.clang-format new file mode 100644 index 0000000..17d6bc4 --- /dev/null +++ b/app/src/main/cpp/Dobby/.clang-format @@ -0,0 +1,18 @@ +BasedOnStyle: LLVM + +IndentWidth: 2 +TabWidth: 2 +UseTab: Never +ColumnLimit: 120 + +FixNamespaceComments: true + +# default is false +#AlignConsecutiveMacros: true +#AlignConsecutiveAssignments: true +#AlignConsecutiveDeclarations: true + +# default is true +ReflowComments: false +SortIncludes : false +AllowShortFunctionsOnASingleLine: false \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/.github/workflows/Builder.yaml b/app/src/main/cpp/Dobby/.github/workflows/Builder.yaml new file mode 100644 index 0000000..015497c --- /dev/null +++ b/app/src/main/cpp/Dobby/.github/workflows/Builder.yaml @@ -0,0 +1,114 @@ +name: Builder + +on: + push: + branches: + - master + +env: + CMAKE_VERSION: 3.20.2 + LLVM_VERSION: 14.0.0 + NDK_VERSION: r25b + +jobs: + delete_latest_release: + runs-on: ubuntu-latest + steps: + - name: checkout master + uses: actions/checkout@master + + - name: delete latest release + uses: dev-drprasad/delete-tag-and-release@v0.2.0 + with: + delete_release: true + tag_name: latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + linux_and_android: + runs-on: ubuntu-latest + needs: delete_latest_release + steps: + - name: checkout master + uses: actions/checkout@master + + - name: init linux cross compile env + run: | + sh scripts/setup_linux_cross_compile.sh + mkdir -p artifact + shell: bash + + - name: compile linux + run: | + python3 scripts/platform_builder.py --platform=linux --arch=all --cmake_dir=$HOME/opt/cmake-$CMAKE_VERSION --llvm_dir=$HOME/opt/llvm-$LLVM_VERSION + cp include/dobby.h build/linux + tar -zcvf build/dobby-linux-all.tar.gz build/linux + cp build/dobby-linux-all.tar.gz artifact/ + + shell: bash + + - name: compile android + run: | + python3 scripts/platform_builder.py --platform=android --arch=all --cmake_dir=$HOME/opt/cmake-$CMAKE_VERSION --llvm_dir=$HOME/opt/llvm-$LLVM_VERSION --android_ndk_dir=$HOME/opt/ndk-$NDK_VERSION + cp include/dobby.h build/android + tar -zcvf build/dobby-android-all.tar.gz build/android + cp build/dobby-android-all.tar.gz artifact/ + shell: bash + + - name: print output + run: | + ls -lha . + + - name: update release + uses: ncipollo/release-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag: latest + body: "a lightweight, multi-platform, multi-architecture exploit hook framework" + artifacts: "build/dobby-linux-all.tar.gz,build/dobby-android-all.tar.gz" + allowUpdates: true + replacesArtifacts: true + + macos_and_iphoneos: + runs-on: macos-latest + needs: delete_latest_release + steps: + - name: checkout dev + uses: actions/checkout@master + + - name: init macos compile env + run: | + sh scripts/setup_macos_cross_compile.sh + mkdir -p artifact + shell: bash + + - name: compile macos + run: | + python3 scripts/platform_builder.py --platform=macos --arch=all --cmake_dir=$HOME/opt/cmake-$CMAKE_VERSION/CMake.app/Contents + cp include/dobby.h build/macos + tar -zcvf build/dobby-macos-all.tar.gz build/macos + cp build/dobby-macos-all.tar.gz artifact/ + + shell: bash + + - name: compile iphoneos + run: | + python3 scripts/platform_builder.py --platform=iphoneos --arch=all --cmake_dir=$HOME/opt/cmake-$CMAKE_VERSION/CMake.app/Contents + cp include/dobby.h build/iphoneos + tar -zcvf build/dobby-iphoneos-all.tar.gz build/iphoneos + cp build/dobby-iphoneos-all.tar.gz artifact/ + shell: bash + + - name: print output + run: | + ls -lha . + + - name: update release + uses: ncipollo/release-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag: latest + body: "a lightweight, multi-platform, multi-architecture exploit hook framework" + artifacts: "build/dobby-macos-all.tar.gz,build/dobby-iphoneos-all.tar.gz" + allowUpdates: true + replacesArtifacts: true \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/.gitignore b/app/src/main/cpp/Dobby/.gitignore new file mode 100644 index 0000000..4bbed76 --- /dev/null +++ b/app/src/main/cpp/Dobby/.gitignore @@ -0,0 +1,80 @@ +.DS_Store +.idea/ +*-build*/ +build-output/ + +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Prefab +/prefab/**/*.a +/prefab/**/*.h +/AndroidManifest.xml diff --git a/app/src/main/cpp/Dobby/.vscode/c_cpp_properties.json b/app/src/main/cpp/Dobby/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..c624a58 --- /dev/null +++ b/app/src/main/cpp/Dobby/.vscode/c_cpp_properties.json @@ -0,0 +1,74 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "/usr/local/include", + "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1", + "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", + "${workspaceRoot}" + ], + "defines": [], + "intelliSenseMode": "clang-x64", + "browse": { + "path": [ + "/usr/local/include", + "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", + "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1", + "${workspaceRoot}" + ], + "limitSymbolsToIncludedHeaders": true, + "databaseFilename": "" + }, + "macFrameworkPath": [ + "/System/Library/Frameworks", + "/Library/Frameworks" + ], + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++11", + "configurationProvider": "vector-of-bool.cmake-tools", + "compileCommands": "${workspaceRoot}/ninja-build/compile_commands.json" + }, + { + "name": "Linux", + "includePath": [ + "/usr/include", + "/usr/local/include", + "${workspaceRoot}" + ], + "defines": [], + "intelliSenseMode": "clang-x64", + "browse": { + "path": [ + "/usr/include", + "/usr/local/include", + "${workspaceRoot}" + ], + "limitSymbolsToIncludedHeaders": true, + "databaseFilename": "" + } + }, + { + "name": "Win32", + "includePath": [ + "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include", + "${workspaceRoot}" + ], + "defines": [ + "_DEBUG", + "UNICODE" + ], + "intelliSenseMode": "msvc-x64", + "browse": { + "path": [ + "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*", + "${workspaceRoot}" + ], + "limitSymbolsToIncludedHeaders": true, + "databaseFilename": "" + } + } + ], + "version": 4 +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/.vscode/launch.json b/app/src/main/cpp/Dobby/.vscode/launch.json new file mode 100644 index 0000000..36ab19f --- /dev/null +++ b/app/src/main/cpp/Dobby/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "(lldb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "enter program name, for example ${workspaceRoot}/a.out", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceRoot}", + "environment": [], + "externalConsole": true, + "MIMode": "lldb" + } + ] +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/.vscode/settings.json b/app/src/main/cpp/Dobby/.vscode/settings.json new file mode 100644 index 0000000..e925cff --- /dev/null +++ b/app/src/main/cpp/Dobby/.vscode/settings.json @@ -0,0 +1,121 @@ +{ + "files.autoSave": "onFocusChange", + "files.autoSaveDelay": 3000, + "editor.formatOnSave": true, + "cmake.environment": { + "ANDROID_NDK": "/Users/jmpews/Library/Android/sdk/ndk-bundle" + }, + "cmake.configureArgs": [ + "-DCMAKE_SYSTEM_NAME=Android", + "-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a", + "-DCMAKE_ANDROID_NDK=/Users/jmpews/Library/Android/sdk/ndk/21.3.6528147", + "-DCMAKE_SYSTEM_VERSION=16", + "-DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang" + ], + "cmake.buildArgs": [], + "cmake.buildToolArgs": [], + "cmake.parallelJobs": 1, + "files.associations": { + "stack": "cpp", + "regex": "cpp", + "bitset": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "__bit_reference": "cpp", + "__functional_base": "cpp", + "algorithm": "cpp", + "atomic": "cpp", + "chrono": "cpp", + "deque": "cpp", + "optional": "cpp", + "limits": "cpp", + "locale": "cpp", + "ratio": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "vector": "cpp", + "utility": "cpp", + "__functional_03": "cpp", + "__locale": "cpp", + "__hash_table": "cpp", + "__split_buffer": "cpp", + "__tree": "cpp", + "hash_map": "cpp", + "hash_set": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "string_view": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "initializer_list": "cpp", + "hashtable": "cpp", + "__config": "cpp", + "__nullptr": "cpp", + "cstddef": "cpp", + "exception": "cpp", + "new": "cpp", + "stdexcept": "cpp", + "typeinfo": "cpp", + "*.tcc": "cpp", + "xstring": "cpp", + "xlocmon": "cpp", + "xtr1common": "cpp", + "list": "cpp", + "xhash": "cpp", + "xtree": "cpp", + "xutility": "cpp", + "iosfwd": "cpp", + "__debug": "cpp", + "__mutex_base": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tuple": "cpp", + "cctype": "cpp", + "cstdarg": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "ios": "cpp", + "iostream": "cpp", + "istream": "cpp", + "mutex": "cpp", + "ostream": "cpp", + "streambuf": "cpp", + "cmath": "cpp", + "array": "cpp", + "fstream": "cpp", + "stdio.h": "c", + "__functional_base_03": "cpp", + "filesystem": "cpp", + "queue": "cpp", + "random": "cpp", + "__errc": "cpp", + "__node_handle": "cpp", + "bit": "cpp", + "complex": "cpp", + "iomanip": "cpp", + "sstream": "cpp", + "stdarg.h": "c", + "clocale": "cpp", + "codecvt": "cpp", + "condition_variable": "cpp", + "numeric": "cpp", + "shared_mutex": "cpp", + "thread": "cpp", + "memory_resource": "cpp", + "cinttypes": "cpp", + "shared_cache_internal.h": "c", + "coroutine": "cpp", + "__bits": "cpp" + }, + "C_Cpp.configurationWarnings": "Disabled", + "lldb.showDisassembly": "auto", + "lldb.dereferencePointers": true, +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/.vscode/tags b/app/src/main/cpp/Dobby/.vscode/tags new file mode 100644 index 0000000..db0ba7e --- /dev/null +++ b/app/src/main/cpp/Dobby/.vscode/tags @@ -0,0 +1,13 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.8 // +HookZzCodeSegment ../tools/zzsolidifyhook.py /^HookZzCodeSegment = [$/;" kind:variable line:4 +lief ../tools/zzsolidifyhook.py /^import lief$/;" kind:namespace line:2 +new_target_file ../tools/zzsolidifyhook.py /^new_target_file = "\/Users\/jmpews\/Desktop\/test\/test.hook.dylib"$/;" kind:variable line:31 +target_file ../tools/zzsolidifyhook.py /^target_file = "\/Users\/jmpews\/Desktop\/test\/test.dylib"$/;" kind:variable line:30 +zz_macho_get_segment_with_name ../tools/zzsolidifyhook.py /^def zz_macho_get_segment_with_name(target_parsed, seg_name):$/;" kind:function line:13 +zz_macho_insert_segment ../tools/zzsolidifyhook.py /^def zz_macho_insert_segment(target_file, new_target_file):$/;" kind:function line:20 +zzsolidifyhook.py ../tools/zzsolidifyhook.py 1;" kind:file line:1 diff --git a/app/src/main/cpp/Dobby/CMakeLists.txt b/app/src/main/cpp/Dobby/CMakeLists.txt new file mode 100644 index 0000000..20f87f0 --- /dev/null +++ b/app/src/main/cpp/Dobby/CMakeLists.txt @@ -0,0 +1,362 @@ +cmake_minimum_required(VERSION 3.5) +project(Dobby) +enable_language(ASM) + +include(cmake/Util.cmake) +include(cmake/Macros.cmake) +include(cmake/build_environment_check.cmake) +include(cmake/auto_source_group.cmake) +include(cmake/xcode_generator_helper.cmake) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_C_STANDARD 11) + +auto_source_group("." "auto-source-group" "\\.(cc|cpp|c|h)$") + +# ===== handle option ===== + +option(DOBBY_GENERATE_SHARED "Build shared library" ON) + +option(DOBBY_DEBUG "Enable debug logging" OFF) + +option(NearBranch "Enable near branch trampoline" ON) + +option(FullFloatingPointRegisterPack "Save and pack all floating-point registers" OFF) + +option(Plugin.SymbolResolver "Enable symbol resolver" ON) + +option(Plugin.ImportTableReplace "Enable import table replace " OFF) + +option(Plugin.Android.BionicLinkerUtil "Enable android bionic linker util" OFF) + +option(BUILD_EXAMPLE "Build example" OFF) + +option(BUILD_TEST "Build test" OFF) + +# private +option(Obfuscation "Enable llvm obfuscation" OFF) + +# private +option(BUILD_KERNEL_MODE "Build xnu kernel mode" OFF) + +# Enable debug will log more information +if ((NOT DEFINED CMAKE_BUILD_TYPE) OR (CMAKE_BUILD_TYPE STREQUAL "Debug")) + set(DOBBY_DEBUG ON) +endif () + +if (DOBBY_DEBUG) + add_definitions(-DDOBBY_DEBUG) + add_definitions(-DLOGGING_DEBUG) + message(STATUS "[Dobby] Enable debug logging") +endif () + +# Enable full floating point register pack +# for arm64, allow access q8 - q31 +if (FullFloatingPointRegisterPack) + add_definitions(-DFULL_FLOATING_POINT_REGISTER_PACK) + message(STATUS "[Dobby] Save and pack all floating-point registers") +endif () + +if (BUILD_KERNEL_MODE) + set(BUILDING_KERNEL ON) + add_definitions(-DBUILDING_KERNEL) + message(STATUS "[Dobby] Build xnu kernel mode") +endif () + +if (CMAKE_GENERATOR STREQUAL Xcode) +endif () + +include(cmake/compiler_and_linker.cmake) + +# --- + +include_directories( + . + ./include + ./source + ./source/include + + ./external + ./external/logging + + ./builtin-plugin +) + +if (SYSTEM.Darwin AND BUILDING_KERNEL) + include_directories( + source/Backend/KernelMode + ) +else () + include_directories( + source/Backend/UserMode + ) +endif () + +# --- + +set(DOBBY_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + # cpu + source/core/arch/CpuFeature.cc + source/core/arch/CpuRegister.cc + + # assembler + source/core/assembler/assembler.cc + source/core/assembler/assembler-arm.cc + source/core/assembler/assembler-arm64.cc + source/core/assembler/assembler-ia32.cc + source/core/assembler/assembler-x64.cc + + # codegen + source/core/codegen/codegen-arm.cc + source/core/codegen/codegen-arm64.cc + source/core/codegen/codegen-ia32.cc + source/core/codegen/codegen-x64.cc + + # memory kit + source/MemoryAllocator/CodeBuffer/CodeBufferBase.cc + source/MemoryAllocator/AssemblyCodeBuilder.cc + source/MemoryAllocator/MemoryAllocator.cc + + # instruction relocation + source/InstructionRelocation/arm/InstructionRelocationARM.cc + source/InstructionRelocation/arm64/InstructionRelocationARM64.cc + source/InstructionRelocation/x86/InstructionRelocationX86.cc + source/InstructionRelocation/x86/InstructionRelocationX86Shared.cc + source/InstructionRelocation/x64/InstructionRelocationX64.cc + source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.c + + # intercept routing + source/InterceptRouting/InterceptRouting.cpp + + # intercept routing trampoline + source/TrampolineBridge/Trampoline/arm/trampoline_arm.cc + source/TrampolineBridge/Trampoline/arm64/trampoline_arm64.cc + source/TrampolineBridge/Trampoline/x86/trampoline_x86.cc + source/TrampolineBridge/Trampoline/x64/trampoline_x64.cc + + # closure trampoline bridge - arm + source/TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm/helper_arm.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm/closure_bridge_arm.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm/ClosureTrampolineARM.cc + # closure trampoline bridge - arm64 + source/TrampolineBridge/ClosureTrampolineBridge/arm64/helper_arm64.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm64/closure_bridge_arm64.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm64/ClosureTrampolineARM64.cc + # closure trampoline bridge - x86 + source/TrampolineBridge/ClosureTrampolineBridge/x86/helper_x86.cc + source/TrampolineBridge/ClosureTrampolineBridge/x86/closure_bridge_x86.cc + source/TrampolineBridge/ClosureTrampolineBridge/x86/ClosureTrampolineX86.cc + # closure trampoline bridge - x64 + source/TrampolineBridge/ClosureTrampolineBridge/x64/helper_x64.cc + source/TrampolineBridge/ClosureTrampolineBridge/x64/closure_bridge_x64.cc + source/TrampolineBridge/ClosureTrampolineBridge/x64/ClosureTrampolineX64.cc + + source/InterceptRouting/Routing/InstructionInstrument/InstructionInstrument.cc + source/InterceptRouting/Routing/InstructionInstrument/RoutingImpl.cc + source/InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.cc + + source/InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHook.cc + source/InterceptRouting/Routing/FunctionInlineHook/RoutingImpl.cc + + # plugin register + source/InterceptRouting/RoutingPlugin/RoutingPlugin.cc + + # main + source/dobby.cpp + source/Interceptor.cpp + source/InterceptEntry.cpp + ) + +if (SYSTEM.Darwin AND BUILDING_KERNEL) + set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + # platform util + source/Backend/KernelMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc + + # kernel mode - platform interface + source/Backend/KernelMode/UnifiedInterface/platform-darwin.cc + source/Backend/KernelMode/UnifiedInterface/exec_mem_placeholder.asm + + # kernel mode - executable memory + source/Backend/KernelMode/ExecMemory/code-patch-tool-darwin.cc + source/Backend/KernelMode/ExecMemory/clear-cache-tool-all.c + ) +elseif (SYSTEM.Darwin) + set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + # platform util + source/Backend/UserMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc + + # user mode - platform interface + source/Backend/UserMode/UnifiedInterface/platform-posix.cc + + # user mode - executable memory + source/Backend/UserMode/ExecMemory/code-patch-tool-darwin.cc + source/Backend/UserMode/ExecMemory/clear-cache-tool-all.c + ) + +elseif (SYSTEM.Linux OR SYSTEM.Android) + set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + # platform util + source/Backend/UserMode/PlatformUtil/Linux/ProcessRuntimeUtility.cc + + # user mode - platform interface + source/Backend/UserMode/UnifiedInterface/platform-posix.cc + + # user mode - executable memory + source/Backend/UserMode/ExecMemory/code-patch-tool-posix.cc + source/Backend/UserMode/ExecMemory/clear-cache-tool-all.c + ) +elseif (SYSTEM.Windows) + set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + # platform util + source/Backend/UserMode/PlatformUtil/Windows/ProcessRuntimeUtility.cc + + # user mode - platform interface + source/Backend/UserMode/UnifiedInterface/platform-windows.cc + + # user mode - executable memory + source/Backend/UserMode/ExecMemory/code-patch-tool-windows.cc + source/Backend/UserMode/ExecMemory/clear-cache-tool-all.c + ) +endif () + +if (PROCESSOR.X86_64 OR PROCESSOR.X86) + set(NearBranch ON) +endif () + +# --- + +if (0 AND SYSTEM.iOS AND (NOT BUILDING_KERNEL)) + include_directories( + source/Backend/UserMode/ExecMemory/substrated + ) + add_definitions(-DCODE_PATCH_WITH_SUBSTRATED) + set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + source/Backend/UserMode/ExecMemory/substrated/mach_interface_support + ) +endif () + +# ----- instrument ----- + +if (FunctionWrapper) + set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + # user mode - multi thread support + # source/UserMode/MultiThreadSupport/ThreadSupport.cpp + # source/UserMode/Thread/PlatformThread.cc + # source/UserMode/Thread/platform-thread-${platform1}.cc + ) + message(FATAL_ERROR "[!] FunctionWrapper plugin is not supported") +endif () + +# --- + +if (NearBranch) + message(STATUS "[Dobby] Enable near branch trampoline") + set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/near_trampoline_arm64.cc + source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/NearBranchTrampoline.cc + source/MemoryAllocator/NearMemoryAllocator.cc) +endif () + +# --- + +# add logging library +add_subdirectory(external/logging) +get_target_property(logging.SOURCE_FILE_LIST logging SOURCES) + +# --- + +if (Plugin.SymbolResolver) + message(STATUS "[Dobby] Enable symbol resolver") + include_directories(builtin-plugin/SymbolResolver) + add_subdirectory(builtin-plugin/SymbolResolver) + get_target_property(symbol_resolver.SOURCE_FILE_LIST symbol_resolver SOURCES) + set(dobby.plugin.SOURCE_FILE_LIST ${dobby.plugin.SOURCE_FILE_LIST} + ${symbol_resolver.SOURCE_FILE_LIST} + ) +endif () + +# --- + +set(dobby.HEADER_FILE_LIST + include/dobby.h + ) + +# --- + +# add build version +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") + execute_process( + COMMAND git rev-parse --short --verify HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE VERSION_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (VERSION_COMMIT_HASH) + set(VERSION_REVISION "${VERSION_COMMIT_HASH}") + endif () +endif () +set(DOBBY_BUILD_VERSION "Dobby${VERSION_REVISION}") +add_definitions(-D__DOBBY_BUILD_VERSION__="${DOBBY_BUILD_VERSION}") +message(STATUS "[Dobby] ${DOBBY_BUILD_VERSION}") + +# --- + +if (DOBBY_GENERATE_SHARED) + message(STATUS "[Dobby] Generate shared library") + set(DOBBY_LIBRARY_TYPE SHARED) +else () + message(STATUS "[Dobby] Generate static library") + set(DOBBY_LIBRARY_TYPE STATIC) +endif () +add_library(dobby ${DOBBY_LIBRARY_TYPE} ${dobby.HEADER_FILE_LIST} ${dobby.SOURCE_FILE_LIST} ${logging.SOURCE_FILE_LIST} ${misc_helper.SOURCE_FILE_LIST} ${dobby.plugin.SOURCE_FILE_LIST}) + +# --- + +target_include_directories(dobby PUBLIC include) + +# --- + +if (Obfuscation) + set(linker_flags "${linker_flags} -Wl,-mllvm -Wl,-obfuscator-conf=all") +endif () + +set_target_properties(dobby + PROPERTIES + LINK_FLAGS "${linker_flags}" + COMPILE_FLAGS "${compiler_flags}" + ) + +# --- + +if (SYSTEM.Android) + target_link_libraries(dobby log) + if (PROCESSOR.ARM) + set_target_properties(dobby + PROPERTIES + ANDROID_ARM_MODE arm + ) + endif () +endif () + +if (SYSTEM.Linux) + target_link_libraries(dobby dl) +endif () + +# --- + +if (BUILD_EXAMPLE AND (NOT BUILDING_KERNEL)) + add_subdirectory(examples) +endif () + +if (BUILD_TEST AND (NOT BUILDING_KERNEL)) + add_subdirectory(tests) +endif () + +# --- + +if (SYSTEM.Darwin AND (NOT BUILDING_KERNEL)) + include(cmake/platform/platform-darwin.cmake) +endif () diff --git a/app/src/main/cpp/Dobby/LICENSE b/app/src/main/cpp/Dobby/LICENSE new file mode 100644 index 0000000..f49a4e1 --- /dev/null +++ b/app/src/main/cpp/Dobby/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/README.md b/app/src/main/cpp/Dobby/README.md new file mode 100644 index 0000000..c0c0195 --- /dev/null +++ b/app/src/main/cpp/Dobby/README.md @@ -0,0 +1,26 @@ +## Dobby + +[![Contact me Telegram](https://img.shields.io/badge/Contact%20me-Telegram-blue.svg)](https://t.me/IOFramebuffer) [![Join group Telegram](https://img.shields.io/badge/Join%20group-Telegram-brightgreen.svg)](https://t.me/dobby_group) + +Dobby a lightweight, multi-platform, multi-architecture exploit hook framework. + +- Minimal and modular library +- Multi-platform support(Windows/macOS/iOS/Android/Linux) +- Multiple architecture support(X86, X86-64, ARM, ARM64) + +## Compile + +[docs/compile.md](docs/compile.md) + +## Download + +[download latest library](https://github.com/jmpews/Dobby/releases/tag/latest) + +## Credits + +1. [frida-gum](https://github.com/frida/frida-gum) +2. [minhook](https://github.com/TsudaKageyu/minhook) +3. [substrate](https://github.com/jevinskie/substrate). +4. [v8](https://github.com/v8/v8) +5. [dart](https://github.com/dart-lang/sdk) +6. [vixl](https://git.linaro.org/arm/vixl.git) diff --git a/app/src/main/cpp/Dobby/README_zh-cn.md b/app/src/main/cpp/Dobby/README_zh-cn.md new file mode 100644 index 0000000..2f528b4 --- /dev/null +++ b/app/src/main/cpp/Dobby/README_zh-cn.md @@ -0,0 +1,3 @@ +## Dobby + +**待更新** \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/MGCopyAnswerMonitor.cc b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/MGCopyAnswerMonitor.cc new file mode 100644 index 0000000..ddf2ee2 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/MGCopyAnswerMonitor.cc @@ -0,0 +1,46 @@ +#include "./dobby_monitor.h" + +#include +#include + +#define LOG_TAG "MGCopyAnswer" + +static uintptr_t getCallFirstArg(DobbyRegisterContext *ctx) { + uintptr_t result; +#if defined(_M_X64) || defined(__x86_64__) +#if defined(_WIN32) + result = ctx->general.regs.rcx; +#else + result = ctx->general.regs.rdi; +#endif +#elif defined(__arm64__) || defined(__aarch64__) + result = ctx->general.regs.x0; +#elif defined(__arm__) + result = ctx->general.regs.r0; +#else +#error "Not Support Architecture." +#endif + return result; +} + +void common_handler(DobbyRegisterContext *ctx, const InterceptEntry *info) { + CFStringRef key_ = 0; + key_ = (CFStringRef)getCallFirstArg(ctx); + + char str_key[256] = {0}; + CFStringGetCString(key_, str_key, 256, kCFStringEncodingUTF8); + LOG("[#] MGCopyAnswer:: %s\n", str_key); +} + +#if 0 +__attribute__((constructor)) static void ctor() { + void *lib = dlopen("/usr/lib/libMobileGestalt.dylib", RTLD_NOW); + void *MGCopyAnswer_addr = DobbySymbolResolver("libMobileGestalt.dylib", "MGCopyAnswer"); + + sleep(1); + + dobby_enable_near_branch_trampoline(); + DobbyInstrument((void *)MGCopyAnswer_addr, common_handler); + dobby_disable_near_branch_trampoline(); +} +#endif diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/dynamic_loader_monitor.cc b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/dynamic_loader_monitor.cc new file mode 100644 index 0000000..5de4284 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/dynamic_loader_monitor.cc @@ -0,0 +1,94 @@ +#include /* getenv */ +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "dobby.h" + +#include "common_header.h" + +#define LOG_TAG "DynamicLoaderMonitor" + +std::unordered_map traced_dlopen_handle_list; + +static void *(*orig_dlopen)(const char *__file, int __mode); +static void *fake_dlopen(const char *__file, int __mode) { + void *result = orig_dlopen(__file, __mode); + if (result != NULL && __file) { + char *traced_filename = (char *)malloc(MAXPATHLEN); + // FIXME: strncpy + strcpy(traced_filename, __file); + LOG(1, "[-] dlopen handle: %s", __file); + traced_dlopen_handle_list.insert(std::make_pair(result, (const char *)traced_filename)); + } + return result; +} + +static void *(*orig_loader_dlopen)(const char *filename, int flags, const void *caller_addr); +static void *fake_loader_dlopen(const char *filename, int flags, const void *caller_addr) { + void *result = orig_loader_dlopen(filename, flags, caller_addr); + if (result != NULL) { + char *traced_filename = (char *)malloc(MAXPATHLEN); + // FIXME: strncpy + strcpy(traced_filename, filename); + LOG(1, "[-] dlopen handle: %s", filename); + traced_dlopen_handle_list.insert(std::make_pair(result, (const char *)traced_filename)); + } + return result; +} + +static const char *get_traced_filename(void *handle, bool removed) { + std::unordered_map::iterator it; + it = traced_dlopen_handle_list.find(handle); + if (it != traced_dlopen_handle_list.end()) { + if (removed) + traced_dlopen_handle_list.erase(it); + return it->second; + } + return NULL; +} + +static void *(*orig_dlsym)(void *__handle, const char *__symbol); +static void *fake_dlsym(void *__handle, const char *__symbol) { + const char *traced_filename = get_traced_filename(__handle, false); + if (traced_filename) { + LOG(1, "[-] dlsym: %s, symbol: %s", traced_filename, __symbol); + } + return orig_dlsym(__handle, __symbol); +} + +static int (*orig_dlclose)(void *__handle); +static int fake_dlclose(void *__handle) { + const char *traced_filename = get_traced_filename(__handle, true); + if (traced_filename) { + LOG(1, "[-] dlclose: %s", traced_filename); + free((void *)traced_filename); + } + return orig_dlclose(__handle); +} + +#if 0 +__attribute__((constructor)) static void ctor() { +#if defined(__ANDROID__) +#if 0 + void *dl = dlopen("libdl.so", RTLD_LAZY); + void *__loader_dlopen = dlsym(dl, "__loader_dlopen"); +#endif + DobbyHook((void *)DobbySymbolResolver(NULL, "__loader_dlopen"), (void *)fake_loader_dlopen, + (void **)&orig_loader_dlopen); +#else + DobbyHook((void *)DobbySymbolResolver(NULL, "dlopen"), (void *)fake_dlopen, (void **)&orig_dlopen); +#endif + + DobbyHook((void *)dlsym, (void *)fake_dlsym, (void **)&orig_dlsym); + DobbyHook((void *)dlclose, (void *)fake_dlclose, (void **)&orig_dlclose); +} +#endif diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/file_operation_monitor.cc b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/file_operation_monitor.cc new file mode 100644 index 0000000..d4f09ca --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/file_operation_monitor.cc @@ -0,0 +1,97 @@ +#include /* getenv */ +#include +#include + +#include +#include + +#include +#include + +#include + +#include "./dobby_monitor.h" + +std::unordered_map *TracedFopenFileList; + +FILE *(*orig_fopen)(const char *filename, const char *mode); +FILE *fake_fopen(const char *filename, const char *mode) { + FILE *result = NULL; + result = orig_fopen(filename, mode); + if (result != NULL) { + char *traced_filename = (char *)malloc(MAXPATHLEN); + // FIXME: strncpy + strcpy(traced_filename, filename); + std::cout << "[-] trace file: " << filename << std::endl; + TracedFopenFileList->insert(std::make_pair(result, traced_filename)); + } + return result; +} + +static const char *GetFileDescriptorTraced(FILE *stream, bool removed) { + std::unordered_map::iterator it; + it = TracedFopenFileList->find(stream); + if (it != TracedFopenFileList->end()) { + if (removed) + TracedFopenFileList->erase(it); + return it->second; + } + return NULL; +} + +size_t (*orig_fread)(void *ptr, size_t size, size_t count, FILE *stream); +size_t fake_fread(void *ptr, size_t size, size_t count, FILE *stream) { + const char *file_name = GetFileDescriptorTraced(stream, false); + if (file_name) { + LOG("[-] fread: %s, buffer: %p\n", file_name, ptr); + } + return orig_fread(ptr, size, count, stream); +} + +size_t (*orig_fwrite)(const void *ptr, size_t size, size_t count, FILE *stream); +size_t fake_fwrite(void *ptr, size_t size, size_t count, FILE *stream) { + const char *file_name = GetFileDescriptorTraced(stream, false); + if (file_name) { + LOG("[-] fwrite %s\n from %p\n", file_name, ptr); + } + return orig_fwrite(ptr, size, count, stream); +} + +__attribute__((constructor)) void __main() { + + TracedFopenFileList = new std::unordered_map(); + +#if defined(__APPLE__) +#include +#if (TARGET_OS_IPHONE || TARGET_OS_MAC) + std::ifstream file; + file.open("/System/Library/CoreServices/SystemVersion.plist"); + std::cout << file.rdbuf(); +#endif +#endif + + // DobbyHook((void *)fopen, (void *)fake_fopen, (void **)&orig_fopen); + // DobbyHook((void *)fwrite, (void *)fake_fwrite, (void **)&orig_fwrite); + // DobbyHook((void *)fread, (void *)fake_fread, (void **)&orig_fread); + + char *home = getenv("HOME"); + char *subdir = (char *)"/Library/Caches/"; + + std::string filePath = std::string(home) + std::string(subdir) + "temp.log"; + + char buffer[64]; + memset(buffer, 'B', 64); + + FILE *fd = fopen(filePath.c_str(), "w+"); + if (!fd) + std::cout << "[!] open " << filePath << "failed!\n"; + + fwrite(buffer, 64, 1, fd); + fflush(fd); + fseek(fd, 0, SEEK_SET); + memset(buffer, 0, 64); + + fread(buffer, 64, 1, fd); + + return; +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/memory_operation_instrument.cc b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/memory_operation_instrument.cc new file mode 100644 index 0000000..0298275 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/memory_operation_instrument.cc @@ -0,0 +1,58 @@ +#include "./dobby_monitor.h" + +#include +#include +#include + +static uintptr_t getCallFirstArg(DobbyRegisterContext *ctx) { + uintptr_t result; +#if defined(_M_X64) || defined(__x86_64__) +#if defined(_WIN32) + result = ctx->general.regs.rcx; +#else + result = ctx->general.regs.rdi; +#endif +#elif defined(__arm64__) || defined(__aarch64__) + result = ctx->general.regs.x0; +#elif defined(__arm__) + result = ctx->general.regs.r0; +#else +#error "Not Support Architecture." +#endif + return result; +} + +void format_integer_manually(char *buf, uint64_t integer) { + int tmp = 0; + for (tmp = (int)integer; tmp > 0; tmp = (tmp >> 4)) { + buf += (tmp % 16); + buf--; + } +} + +// [ATTENTION]: +// printf will call 'malloc' internally, and will crash in a loop. +// so, use 'puts' is a better choice. +void malloc_handler(DobbyRegisterContext *ctx, const InterceptEntry *info) { + size_t size_ = 0; + size_ = getCallFirstArg(ctx); + char *buffer_ = (char *)"[-] function malloc first arg: 0x00000000.\n"; + format_integer_manually(strchr(buffer_, '.') - 1, size_); + puts(buffer_); +} + +void free_handler(DobbyRegisterContext *ctx, const InterceptEntry *info) { + uintptr_t mem_ptr; + + mem_ptr = getCallFirstArg(ctx); + + char *buffer = (char *)"[-] function free first arg: 0x00000000.\n"; + format_integer_manually(strchr(buffer, '.') - 1, mem_ptr); + puts(buffer); +} + +__attribute__((constructor)) static void ctor() { + // DobbyInstrument((void *)mmap, malloc_handler); + // DobbyInstrument((void *)free, free_handler); + return; +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/posix_file_descriptor_operation_monitor.cc b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/posix_file_descriptor_operation_monitor.cc new file mode 100644 index 0000000..4aaa2f4 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/posix_file_descriptor_operation_monitor.cc @@ -0,0 +1,120 @@ +#include /* getenv */ +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include "dobby.h" +#include "common_header.h" + +#define LOG_TAG "PosixFileOperationMonitor" + +std::unordered_map *posix_file_descriptors; + +int (*orig_open)(const char *pathname, int flags, ...); +int fake_open(const char *pathname, int flags, ...) { + mode_t mode = 0; + if (flags & O_CREAT) { + va_list args; + va_start(args, flags); + mode = (mode_t)va_arg(args, int); + va_end(args); + } + + int result = orig_open(pathname, flags, mode); + if (result != -1) { + char *traced_filename = (char *)malloc(MAXPATHLEN); + // FIXME: strncpy + strcpy(traced_filename, pathname); + LOG(1, "[-] trace open handle: %s", pathname); + + if (posix_file_descriptors == NULL) { + posix_file_descriptors = new std::unordered_map(); + } + posix_file_descriptors->insert(std::make_pair(result, (const char *)traced_filename)); + } + return result; +} + +int (*orig___open)(const char *pathname, int flags, int mode); +int fake___open(const char *pathname, int flags, int mode) { + char *traced_filename = NULL; + if (pathname) { + traced_filename = (char *)malloc(MAXPATHLEN); + // FIXME: strncpy + strcpy(traced_filename, pathname); + LOG(1, "[-] trace open handle: ", pathname); + } + int result = orig___open(pathname, flags, mode); + if (result != -1) { + if (posix_file_descriptors == NULL) { + posix_file_descriptors = new std::unordered_map(); + } + posix_file_descriptors->insert(std::make_pair(result, (const char *)traced_filename)); + } + return result; +} + +static const char *get_traced_filename(int fd, bool removed) { + if (posix_file_descriptors == NULL) + return NULL; + std::unordered_map::iterator it; + it = posix_file_descriptors->find(fd); + if (it != posix_file_descriptors->end()) { + if (removed) + posix_file_descriptors->erase(it); + return it->second; + } + return NULL; +} + +ssize_t (*orig_read)(int fd, void *buf, size_t count); +ssize_t fake_read(int fd, void *buf, size_t count) { + const char *traced_filename = get_traced_filename(fd, false); + if (traced_filename) { + LOG(1, "[-] read: %s, buffer: %p, size: %zu", traced_filename, buf, count); + } + return orig_read(fd, buf, count); +} + +ssize_t (*orig_write)(int fd, const void *buf, size_t count); +ssize_t fake_write(int fd, const void *buf, size_t count) { + const char *traced_filename = get_traced_filename(fd, false); + if (traced_filename) { + LOG(1, "[-] write: %s, buffer: %p, size: %zu", traced_filename, buf, count); + } + return orig_write(fd, buf, count); +} +int (*orig_close)(int fd); +int fake_close(int fd) { + const char *traced_filename = get_traced_filename(fd, true); + if (traced_filename) { + LOG(1, "[-] close: %s", traced_filename); + free((void *)traced_filename); + } + return orig_close(fd); +} + +#if 0 +__attribute__((constructor)) static void ctor() { + DobbyHook((void *)DobbySymbolResolver(NULL, "open"), (void *)fake_open, (void **)&orig_open); + + DobbyHook((void *)DobbySymbolResolver(NULL, "write"), (void *)fake_write, (void **)&orig_write); + + DobbyHook((void *)DobbySymbolResolver(NULL, "read"), (void *)fake_read, (void **)&orig_read); + + DobbyHook((void *)DobbySymbolResolver(NULL, "close"), (void *)fake_close, (void **)&orig_close); +} +#endif diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/posix_socket_network_monitor.cc b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/posix_socket_network_monitor.cc new file mode 100644 index 0000000..8314a18 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ApplicationEventMonitor/posix_socket_network_monitor.cc @@ -0,0 +1,57 @@ +#include /* getenv */ +#include +#include + +#include +#include + +#include + +#include + +#include +#include + +std::unordered_map posix_socket_file_descriptors; + +int (*orig_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int fake_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { +} + +static const char *get_traced_socket(int fd, bool removed) { + std::unordered_map::iterator it; + it = posix_socket_file_descriptors.find(fd); + if (it != posix_socket_file_descriptors.end()) { + if (removed) + posix_socket_file_descriptors.erase(it); + return it->second; + } + return NULL; +} + +int (*orig_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int fake_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + const char *traced_socket = get_traced_socket(sockfd, false); + if (traced_socket) { + LOG(1, "[-] connect: %s\n", traced_socket); + } + return orig_connect(sockfd, addr, addrlen); +} + +ssize_t (*orig_send)(int sockfd, const void *buf, size_t len, int flags); +ssize_t fake_send(int sockfd, const void *buf, size_t len, int flags) { + const char *traced_socket = get_traced_socket(sockfd, false); + if (traced_socket) { + LOG(1, "[-] send: %s, buf: %p, len: %zu\n", traced_socket, buf, len); + } + return orig_send(sockfd, buf, len, flags); +} + +ssize_t (*orig_recv)(int sockfd, void *buf, size_t len, int flags); +ssize_t fake_recv(int sockfd, void *buf, size_t len, int flags) { + const char *traced_socket = get_traced_socket(sockfd, false); + if (traced_socket) { + LOG(1, "[-] recv: %s, buf: %p, len: %zu\n", traced_socket, buf, len); + } + return orig_recv(sockfd, buf, len, flags); +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_demo.cc b/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_demo.cc new file mode 100644 index 0000000..095d45b --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_demo.cc @@ -0,0 +1,36 @@ +#include "dobby.h" + +#include "bionic_linker_util.h" + +#include "logging/logging.h" + +#include + +#define LOG_TAG "BionicLinkerUtil" + +__attribute__((constructor)) static void ctor() { + const char *lib = NULL; + +#if defined(__LP64__) + lib = "/system/lib64/libandroid_runtime.so"; +#else + lib = "/system/lib/libandroid_runtime.so"; +#endif + + void *vm = NULL; + + vm = DobbySymbolResolver(lib, "_ZN7android14AndroidRuntime7mJavaVME"); + LOG(1, "DobbySymbolResolver::vm %p", vm); + +#if 0 + linker_disable_namespace_restriction(); + void *handle = NULL; + handle = dlopen(lib, RTLD_LAZY); + vm = dlsym(handle, "_ZN7android14AndroidRuntime7mJavaVME"); +#else + void *handle = NULL; + handle = linker_dlopen(lib, RTLD_LAZY); + vm = dlsym(handle, "_ZN7android14AndroidRuntime7mJavaVME"); +#endif + LOG(1, "vm %p", vm); +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_util.cc b/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_util.cc new file mode 100644 index 0000000..8860ce1 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_util.cc @@ -0,0 +1,197 @@ +#include "bionic_linker_util.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "dobby.h" +#include "dobby_symbol_resolver.h" + +#include "common_header.h" + +#undef LOG_TAG +#define LOG_TAG "BionicLinkerUtil" + +#undef Q +#define Q 29 +// impl at "dobby_symbol_resolver.cc" +extern void *resolve_elf_internal_symbol(const char *library_name, const char *symbol_name); + +#include +static int get_android_system_version() { + char os_version_str[PROP_VALUE_MAX + 1]; + __system_property_get("ro.build.version.sdk", os_version_str); + int os_version_int = atoi(os_version_str); + return os_version_int; +} + +static const char *get_android_linker_path() { +#if __LP64__ + if (get_android_system_version() >= Q) { + return (const char *)"/apex/com.android.runtime/bin/linker64"; + } else { + return (const char *)"/system/bin/linker64"; + } +#else + if (get_android_system_version() >= Q) { + return (const char *)"/apex/com.android.runtime/bin/linker"; + } else { + return (const char *)"/system/bin/linker"; + } +#endif +} + +PUBLIC void *linker_dlopen(const char *filename, int flag) { + typedef void *(*__loader_dlopen_t)(const char *filename, int flags, const void *caller_addr); + static __loader_dlopen_t __loader_dlopen = NULL; + if (!__loader_dlopen) + __loader_dlopen = (__loader_dlopen_t)DobbySymbolResolver(NULL, "__loader_dlopen"); + + // fake caller address + void *open_ptr = dlsym(RTLD_DEFAULT, "open"); + return __loader_dlopen(filename, flag, (const void *)open_ptr); +} + +std::vector linker_solist; +std::vector linker_get_solist() { + if (!linker_solist.empty()) { + linker_solist.clear(); + } + + static soinfo_t (*solist_get_head)() = NULL; + if (!solist_get_head) + solist_get_head = + (soinfo_t(*)())resolve_elf_internal_symbol(get_android_linker_path(), "__dl__Z15solist_get_headv"); + + static soinfo_t (*solist_get_somain)() = NULL; + if (!solist_get_somain) + solist_get_somain = + (soinfo_t(*)())resolve_elf_internal_symbol(get_android_linker_path(), "__dl__Z17solist_get_somainv"); + + static addr_t *solist_head = NULL; + if (!solist_head) + solist_head = (addr_t *)solist_get_head(); + + static addr_t somain = 0; + if (!somain) + somain = (addr_t)solist_get_somain(); + + // Generate the name for an offset. +#define PARAM_OFFSET(type_, member_) __##type_##__##member_##__offset_ +#define STRUCT_OFFSET PARAM_OFFSET + int STRUCT_OFFSET(solist, next) = 0; + for (size_t i = 0; i < 1024 / sizeof(void *); i++) { + if (*(addr_t *)((addr_t)solist_head + i * sizeof(void *)) == somain) { + STRUCT_OFFSET(solist, next) = i * sizeof(void *); + break; + } + } + + linker_solist.push_back(solist_head); + + addr_t sonext = 0; + sonext = *(addr_t *)((addr_t)solist_head + STRUCT_OFFSET(solist, next)); + while (sonext) { + linker_solist.push_back((void *)sonext); + sonext = *(addr_t *)((addr_t)sonext + STRUCT_OFFSET(solist, next)); + } + + return linker_solist; +} + +char *linker_soinfo_get_realpath(soinfo_t soinfo) { + static char *(*_get_realpath)(soinfo_t) = NULL; + if (!_get_realpath) + _get_realpath = + (char *(*)(soinfo_t))resolve_elf_internal_symbol(get_android_linker_path(), "__dl__ZNK6soinfo12get_realpathEv"); + return _get_realpath(soinfo); +} + +uintptr_t linker_soinfo_to_handle(soinfo_t soinfo) { + static uintptr_t (*_linker_soinfo_to_handle)(soinfo_t) = NULL; + if (!_linker_soinfo_to_handle) + _linker_soinfo_to_handle = + (uintptr_t(*)(soinfo_t))resolve_elf_internal_symbol(get_android_linker_path(), "__dl__ZN6soinfo9to_handleEv"); + return _linker_soinfo_to_handle(soinfo); +} + +typedef void *android_namespace_t; +android_namespace_t linker_soinfo_get_primary_namespace(soinfo_t soinfo) { + static android_namespace_t (*_get_primary_namespace)(soinfo_t) = NULL; + if (!_get_primary_namespace) + _get_primary_namespace = (android_namespace_t(*)(soinfo_t))resolve_elf_internal_symbol( + get_android_linker_path(), "__dl__ZN6soinfo21get_primary_namespaceEv"); + return _get_primary_namespace(soinfo); +} + +void linker_iterate_soinfo(int (*cb)(soinfo_t soinfo)) { + auto solist = linker_get_solist(); + for (auto it = solist.begin(); it != solist.end(); it++) { + int ret = cb(*it); + if (ret != 0) + break; + } +} + +static int iterate_soinfo_cb(soinfo_t soinfo) { + android_namespace_t ns = NULL; + ns = linker_soinfo_get_primary_namespace(soinfo); + LOG(1, "lib: %s", linker_soinfo_get_realpath(soinfo)); + + // set is_isolated_ as false + // no need for this actually + int STRUCT_OFFSET(android_namespace_t, is_isolated_) = 0x8; + *(uint8_t *)((addr_t)ns + STRUCT_OFFSET(android_namespace_t, is_isolated_)) = false; + + std::vector ld_library_paths = {"/system/lib64", "/sytem/lib"}; + if (get_android_system_version() >= Q) { + ld_library_paths.push_back("/apex/com.android.runtime/lib64"); + ld_library_paths.push_back("/apex/com.android.runtime/lib"); + } + int STRUCT_OFFSET(android_namespace_t, ld_library_paths_) = 0x10; + if (*(void **)((addr_t)ns + STRUCT_OFFSET(android_namespace_t, ld_library_paths_))) { + std::vector orig_ld_library_paths = + *(std::vector *)((addr_t)ns + STRUCT_OFFSET(android_namespace_t, ld_library_paths_)); + orig_ld_library_paths.insert(orig_ld_library_paths.end(), ld_library_paths.begin(), ld_library_paths.end()); + + // remove duplicates + { + std::set paths(orig_ld_library_paths.begin(), orig_ld_library_paths.end()); + orig_ld_library_paths.assign(paths.begin(), paths.end()); + } + } else { + *(std::vector *)((addr_t)ns + STRUCT_OFFSET(android_namespace_t, ld_library_paths_)) = + std::move(ld_library_paths); + } + return 0; +} + +bool (*orig_linker_namespace_is_is_accessible)(android_namespace_t ns, const std::string &file); +bool linker_namespace_is_is_accessible(android_namespace_t ns, const std::string &file) { + LOG(1, "check %s", file.c_str()); + return true; + return orig_linker_namespace_is_is_accessible(ns, file); +} + +void linker_disable_namespace_restriction() { + linker_iterate_soinfo(iterate_soinfo_cb); + + // no need for this actually + void *linker_namespace_is_is_accessible_ptr = resolve_elf_internal_symbol( + get_android_linker_path(), "__dl__ZN19android_namespace_t13is_accessibleERKNSt3__112basic_" + "stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE"); + DobbyHook(linker_namespace_is_is_accessible_ptr, (void *)linker_namespace_is_is_accessible, + (void **)&orig_linker_namespace_is_is_accessible); + + LOG(1, "disable namespace restriction done"); +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_util.h b/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_util.h new file mode 100644 index 0000000..55c2911 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/BionicLinkerUtil/bionic_linker_util.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *soinfo_t; + +soinfo_t linker_dlopen(const char *filename, int flag); + +char *linker_soinfo_get_realpath(soinfo_t soinfo); + +uintptr_t linker_soinfo_to_handle(soinfo_t soinfo); + +void linker_iterate_soinfo(int (*cb)(soinfo_t soinfo)); + +void linker_disable_namespace_restriction(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/CMakeLists.txt b/app/src/main/cpp/Dobby/builtin-plugin/CMakeLists.txt new file mode 100644 index 0000000..3730cb9 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/CMakeLists.txt @@ -0,0 +1,15 @@ +if (Plugin.ImportTableReplace AND SYSTEM.Darwin) + message(STATUS "[Dobby] Enable got hook") + include_directories(builtin-plugin/ImportTableReplace) + add_subdirectory(builtin-plugin/ImportTableReplace) +endif () + +if (Plugin.Android.BionicLinkerUtil) + if (NOT SYSTEM.Android) + message(FATAL_ERROR "[!] Plugin.Android.BionicLinkerUtil only works on Android.") + endif () + message(STATUS "[Dobby] Enable Plugin.Android.BionicLinkerUtil") + set(dobby.plugin.SOURCE_FILE_LIST ${dobby.plugin.SOURCE_FILE_LIST} + BionicLinkerUtil/bionic_linker_util.cc + ) +endif () \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/CMakeLists.txt b/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/CMakeLists.txt new file mode 100644 index 0000000..44c513a --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(import_table_repalce INTERFACE + dobby_import_replace.cc + ) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/dobby_import_replace.cc b/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/dobby_import_replace.cc new file mode 100644 index 0000000..900f063 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/dobby_import_replace.cc @@ -0,0 +1,192 @@ +#include "dobby_import_replace.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include "common_header.h" + +#include "logging/logging.h" + +#include "PlatformUtil/ProcessRuntimeUtility.h" + +#if defined(__LP64__) +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +static void *iterate_indirect_symtab(char *symbol_name, section_t *section, intptr_t slide, nlist_t *symtab, + char *strtab, uint32_t *indirect_symtab) { + const bool is_data_const = strcmp(section->segname, "__DATA_CONST") == 0; + uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; + void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); + + vm_prot_t old_protection = VM_PROT_READ; + if (is_data_const) { + mprotect(indirect_symbol_bindings, section->size, PROT_READ | PROT_WRITE); + } + + for (uint i = 0; i < section->size / sizeof(void *); i++) { + uint32_t symtab_index = indirect_symbol_indices[i]; + if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || + symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { + continue; + } + uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; + char *local_symbol_name = strtab + strtab_offset; + bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; + if (strcmp(local_symbol_name, symbol_name) == 0) { + return &indirect_symbol_bindings[i]; + } + if (local_symbol_name[0] == '_') { + if (strcmp(symbol_name, &local_symbol_name[1]) == 0) { + return &indirect_symbol_bindings[i]; + } + } + } + + if (is_data_const && 0) { + int protection = 0; + if (old_protection & VM_PROT_READ) { + protection |= PROT_READ; + } + if (old_protection & VM_PROT_WRITE) { + protection |= PROT_WRITE; + } + if (old_protection & VM_PROT_EXECUTE) { + protection |= PROT_EXEC; + } + mprotect(indirect_symbol_bindings, section->size, protection); + } + return NULL; +} + +static void *get_global_offset_table_stub(mach_header_t *header, char *symbol_name) { + segment_command_t *curr_seg_cmd; + segment_command_t *text_segment, *data_segment, *linkedit_segment; + struct symtab_command *symtab_cmd = NULL; + struct dysymtab_command *dysymtab_cmd = NULL; + + uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += curr_seg_cmd->cmdsize) { + curr_seg_cmd = (segment_command_t *)cur; + if (curr_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(curr_seg_cmd->segname, "__LINKEDIT") == 0) { + linkedit_segment = curr_seg_cmd; + } else if (strcmp(curr_seg_cmd->segname, "__DATA") == 0) { + data_segment = curr_seg_cmd; + } else if (strcmp(curr_seg_cmd->segname, "__TEXT") == 0) { + text_segment = curr_seg_cmd; + } + } else if (curr_seg_cmd->cmd == LC_SYMTAB) { + symtab_cmd = (struct symtab_command *)curr_seg_cmd; + } else if (curr_seg_cmd->cmd == LC_DYSYMTAB) { + dysymtab_cmd = (struct dysymtab_command *)curr_seg_cmd; + } + } + + if (!symtab_cmd || !linkedit_segment || !linkedit_segment) { + return NULL; + } + + uintptr_t slide = (uintptr_t)header - (uintptr_t)text_segment->vmaddr; + uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; + nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); + char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); + uint32_t symtab_count = symtab_cmd->nsyms; + + uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); + + cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += curr_seg_cmd->cmdsize) { + curr_seg_cmd = (segment_command_t *)cur; + if (curr_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(curr_seg_cmd->segname, "__DATA") != 0 && strcmp(curr_seg_cmd->segname, "__DATA_CONST") != 0) { + continue; + } + for (uint j = 0; j < curr_seg_cmd->nsects; j++) { + section_t *sect = (section_t *)(cur + sizeof(segment_command_t)) + j; + if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { + void *stub = iterate_indirect_symtab(symbol_name, sect, slide, symtab, strtab, indirect_symtab); + if (stub) + return stub; + } + if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { + void *stub = iterate_indirect_symtab(symbol_name, sect, slide, symtab, strtab, indirect_symtab); + if (stub) + return stub; + } + } + } + } + + return NULL; +} + +PUBLIC int DobbyImportTableReplace(char *image_name, char *symbol_name, void *fake_func, void **orig_func_ptr) { + std::vector ProcessModuleMap = ProcessRuntimeUtility::GetProcessModuleMap(); + + for (auto module : ProcessModuleMap) { + if (image_name != NULL && strstr(module.path, image_name) == NULL) + continue; + + addr_t header = (addr_t)module.load_address; + size_t slide = 0; + +#if 0 + if (header) { + if (((struct mach_header *)header)->magic == MH_MAGIC_64) + slide = macho_kit_get_slide64(header); + } +#endif + +#if 0 + LOG(1, "resolve image: %s", module.path); +#endif + + uint32_t nlist_count = 0; + nlist_t *nlist_array = 0; + char *string_pool = 0; + + void *stub = get_global_offset_table_stub((mach_header_t *)header, symbol_name); + if (stub) { + void *orig_func; + orig_func = *(void **)stub; +#if __has_feature(ptrauth_calls) + orig_func = ptrauth_strip(orig_func, ptrauth_key_asia); + orig_func = ptrauth_sign_unauthenticated(orig_func, ptrauth_key_asia, 0); +#endif + *orig_func_ptr = orig_func; + +#if __has_feature(ptrauth_calls) + fake_func = (void *)ptrauth_strip(fake_func, ptrauth_key_asia); + fake_func = ptrauth_sign_unauthenticated(fake_func, ptrauth_key_asia, stub); +#endif + *(void **)stub = fake_func; + } + + if (image_name) + return 0; + } + return -1; +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/dobby_import_replace.h b/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/dobby_import_replace.h new file mode 100644 index 0000000..c51b0f7 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ImportTableReplace/dobby_import_replace.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// int DobbyImportTableReplace(char *image_name, char *symbol_name, void *fake_func, void **orig_func); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/CMakeLists.txt b/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/CMakeLists.txt new file mode 100644 index 0000000..754610b --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(objc_runtime_replace + objc_runtime_replace.mm + ) + +target_link_libraries(objc_runtime_replace + "-framework Foundation" + ) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/objc_runtime_repalce.h b/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/objc_runtime_repalce.h new file mode 100644 index 0000000..da959e7 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/objc_runtime_repalce.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +IMP DobbyObjcReplace(Class _class, SEL _selector, IMP replacement); + +void DobbyObjcReplaceEx(const char *class_name, const char *selector_name, void *fake_impl, void **orig_impl); + +void *DobbyObjcResolveMethodImp(const char *class_name, const char *selector_name); + +#ifdef __cplusplus +} +#endif diff --git a/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/objc_runtime_replace.mm b/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/objc_runtime_replace.mm new file mode 100644 index 0000000..bd57340 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/ObjcRuntimeReplace/objc_runtime_replace.mm @@ -0,0 +1,56 @@ +#include "ObjcRuntimeReplace/objc_runtime_repalce.h" +#include "dobby_internal.h" + +#include +#include + +/* clang -rewrite-objc main.m */ + +IMP DobbyObjcReplace(Class class_, SEL sel_, IMP fake_impl) { + Method method_ = class_getInstanceMethod(class_, sel_); + if (!method_) + method_ = class_getClassMethod(class_, sel_); + + if (!method_) { + DLOG(0, "Not found class: %s, selector: %s method\n", class_getName(class_), sel_getName(sel_)); + return NULL; + } + + return method_setImplementation(method_, (IMP)fake_impl); +} + +void DobbyObjcReplaceEx(const char *class_name, const char *selector_name, void *fake_impl, void **out_orig_impl) { + Class class_ = objc_getClass(class_name); + SEL sel_ = sel_registerName(selector_name); + + Method method_ = class_getInstanceMethod(class_, sel_); + if (!method_) + method_ = class_getClassMethod(class_, sel_); + + if (!method_) { + DLOG(0, "Not found class: %s, selector: %s method\n", class_name, selector_name); + return; + } + + void *orig_impl = NULL; + orig_impl = (void *)method_setImplementation(method_, (IMP)fake_impl); + if (out_orig_impl) { + *out_orig_impl = orig_impl; + } + return; +} + +void *DobbyObjcResolveMethodImp(const char *class_name, const char *selector_name) { + Class class_ = objc_getClass(class_name); + SEL sel_ = sel_registerName(selector_name); + + Method method_ = class_getInstanceMethod(class_, sel_); + if (!method_) + method_ = class_getClassMethod(class_, sel_); + + if (!method_) { + DLOG(0, "Not found class: %s, selector: %s method\n", class_name, selector_name); + return NULL; + } + return (void *)method_getImplementation(method_); +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/CMakeLists.txt b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/CMakeLists.txt new file mode 100644 index 0000000..ddddfd7 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/CMakeLists.txt @@ -0,0 +1,23 @@ +add_library(supervisor_call_monitor STATIC + mach_system_call_log_handler.cc + system_call_log_handler.cc + supervisor_call_monitor.cc + sensitive_api_monitor.cc + misc_utility.cc + ) +target_link_libraries(supervisor_call_monitor + misc_helper + dobby + ) + +add_library(test_supervisor_call_monitor SHARED + test_supervisor_call_monitor.cc + ) +target_link_libraries(test_supervisor_call_monitor + supervisor_call_monitor +) + +include_directories( + . +) + diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/README b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/README new file mode 100644 index 0000000..3832eb5 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/README @@ -0,0 +1 @@ +Monitor all supervisor call \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/mach_system_call_log_handler.cc b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/mach_system_call_log_handler.cc new file mode 100644 index 0000000..25b2043 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/mach_system_call_log_handler.cc @@ -0,0 +1,193 @@ +#include "dobby_internal.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "misc-helper/async_logger.h" +#include "PlatformUtil/ProcessRuntimeUtility.h" +#include "SupervisorCallMonitor/misc_utility.h" +#include "SupervisorCallMonitor/supervisor_call_monitor.h" + +#include "XnuInternal/syscall_sw.c" + +#include "XnuInternal/mach/clock_priv.h" +#include "XnuInternal/mach/clock_reply.h" +#include "XnuInternal/mach/clock.h" +#include "XnuInternal/mach/exc.h" +#include "XnuInternal/mach/host_priv.h" +#include "XnuInternal/mach/host_security.h" +#include "XnuInternal/mach/lock_set.h" +#include "XnuInternal/mach/mach_host.h" +#include "XnuInternal/mach/mach_port.h" +#include "XnuInternal/mach/mach_vm.h" +#include "XnuInternal/mach/mach_voucher.h" +#include "XnuInternal/mach/memory_entry.h" +#include "XnuInternal/mach/processor_set.h" +#include "XnuInternal/mach/processor.h" +#include "XnuInternal/mach/task.h" +#include "XnuInternal/mach/thread_act.h" +#include "XnuInternal/mach/vm_map.h" + +typedef struct { + char *mach_msg_name; + int mach_msg_id; +} mach_msg_entry_t; + +// clang-format off +mach_msg_entry_t mach_msg_array[] = { + subsystem_to_name_map_clock_priv, + subsystem_to_name_map_clock_reply, + subsystem_to_name_map_clock, + subsystem_to_name_map_exc, + subsystem_to_name_map_host_priv, + subsystem_to_name_map_host_security, + subsystem_to_name_map_lock_set, + subsystem_to_name_map_mach_host, + subsystem_to_name_map_mach_port, + subsystem_to_name_map_mach_vm, + subsystem_to_name_map_mach_voucher, + subsystem_to_name_map_memory_entry, + subsystem_to_name_map_processor_set, + subsystem_to_name_map_processor, + subsystem_to_name_map_task, + subsystem_to_name_map_thread_act, + subsystem_to_name_map_vm_map, +}; +// clang-format on + +#define PRIME_NUMBER 8387 +char *mach_msg_name_table[PRIME_NUMBER] = {0}; +static int hash_mach_msg_num_to_ndx(int mach_msg_num) { + return mach_msg_num % PRIME_NUMBER; +} +static void mach_msg_id_hash_table_init() { + static bool initialized = false; + if (initialized == true) { + return; + } + initialized = true; + + int count = sizeof(mach_msg_array) / sizeof(mach_msg_array[0]); + for (size_t i = 0; i < count; i++) { + mach_msg_entry_t entry = mach_msg_array[i]; + int ndx = hash_mach_msg_num_to_ndx(entry.mach_msg_id); + mach_msg_name_table[ndx] = entry.mach_msg_name; + } +} + +const char *mach_syscall_num_to_str(int num) { + return mach_syscall_name_table[0 - num]; +} + +char *mach_msg_id_to_str(int msgh_id) { + int ndx = hash_mach_msg_num_to_ndx(msgh_id); + return mach_msg_name_table[ndx]; +} + +char *mach_msg_to_str(mach_msg_header_t *msg) { + static mach_port_t self_port = MACH_PORT_NULL; + + if (self_port == MACH_PORT_NULL) { + self_port = mach_task_self(); + } + + if (msg->msgh_remote_port == self_port) { + return mach_msg_id_to_str(msg->msgh_id); + } + return NULL; +} + +static addr_t getCallFirstArg(DobbyRegisterContext *ctx) { + addr_t result; +#if defined(_M_X64) || defined(__x86_64__) +#if defined(_WIN32) + result = ctx->general.regs.rcx; +#else + result = ctx->general.regs.rdi; +#endif +#elif defined(__arm64__) || defined(__aarch64__) + result = ctx->general.regs.x0; +#elif defined(__arm__) + result = ctx->general.regs.r0; +#else +#error "Not Support Architecture." +#endif + return result; +} + +static addr_t getRealLr(DobbyRegisterContext *ctx) { + addr_t closure_trampoline_reserved_stack = ctx->sp - sizeof(addr_t); + return *(addr_t *)closure_trampoline_reserved_stack; +} + +static addr_t fast_get_caller_from_main_binary(DobbyRegisterContext *ctx) { + static addr_t text_section_start = 0, text_section_end = 0; + static addr_t slide = 0; + if (text_section_start == 0 || text_section_end == 0) { + auto main = ProcessRuntimeUtility::GetProcessModule("mobilex"); + addr_t main_header = (addr_t)main.load_address; + + auto text_segment = macho_kit_get_segment_by_name((mach_header_t *)main_header, "__TEXT"); + slide = main_header - text_segment->vmaddr; + + auto text_section = macho_kit_get_section_by_name((mach_header_t *)main_header, "__TEXT", "__text"); + text_section_start = main_header + (addr_t)text_section->offset; + text_section_end = text_section_start + text_section->size; + } + + if (ctx == NULL) + return 0; + + addr_t lr = getRealLr(ctx); + if (lr > text_section_start && lr < text_section_end) + return lr - slide; + +#define MAX_STACK_ITERATE_LEVEL 8 + addr_t fp = ctx->fp; + if (fp == 0) + return 0; + for (int i = 0; i < MAX_STACK_ITERATE_LEVEL; i++) { + addr_t lr = *(addr_t *)(fp + sizeof(addr_t)); + if (lr > text_section_start && lr < text_section_end) + return lr - slide; + fp = *(addr_t *)fp; + if (fp == 0) + return 0; + } + return 0; +} + +static void mach_syscall_log_handler(DobbyRegisterContext *ctx, const InterceptEntry *info) { + addr_t caller = fast_get_caller_from_main_binary(ctx); + if (caller == 0) + return; + + char buffer[256] = {0}; + int syscall_rum = ctx->general.regs.x16; + if (syscall_rum == -31) { + // mach_msg_trap + mach_msg_header_t *msg = (typeof(msg))getCallFirstArg(ctx); + char *mach_msg_name = mach_msg_to_str(msg); + if (mach_msg_name) { + sprintf(buffer, "[mach msg svc] %s\n", mach_msg_name); + } else { + buffer[0] = 0; + } + } else if (syscall_rum < 0) { + sprintf(buffer, "[mach svc-%d] %s\n", syscall_rum, mach_syscall_num_to_str(syscall_rum)); + } + async_logger_print(buffer); +} + +void supervisor_call_monitor_register_mach_syscall_call_log_handler() { + mach_msg_id_hash_table_init(); + fast_get_caller_from_main_binary(NULL); + supervisor_call_monitor_register_handler(mach_syscall_log_handler); +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/misc_utility.cc b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/misc_utility.cc new file mode 100644 index 0000000..2a0a05b --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/misc_utility.cc @@ -0,0 +1,44 @@ +#include "misc_utility.h" + +#include + +segment_command_t *macho_kit_get_segment_by_name(mach_header_t *header, const char *segname) { + segment_command_t *curr_seg_cmd = NULL; + + curr_seg_cmd = (segment_command_t *)((addr_t)header + sizeof(mach_header_t)); + for (int i = 0; i < header->ncmds; i++) { + if (curr_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (!strncmp(curr_seg_cmd->segname, segname, sizeof(curr_seg_cmd->segname))) { + break; + } + } + curr_seg_cmd = (segment_command_t *)((addr_t)curr_seg_cmd + curr_seg_cmd->cmdsize); + } + + return curr_seg_cmd; +} + +section_t *macho_kit_get_section_by_name(mach_header_t *header, const char *segname, const char *sectname) { + section_t *section = NULL; + segment_command_t *segment = NULL; + + int i = 0; + + segment = macho_kit_get_segment_by_name(header, segname); + if (!segment) + goto finish; + + section = (section_t *)((addr_t)segment + sizeof(segment_command_t)); + for (i = 0; i < segment->nsects; ++i) { + if (!strncmp(section->sectname, sectname, sizeof(section->sectname))) { + break; + } + section += 1; + } + if (i == segment->nsects) { + section = NULL; + } + +finish: + return section; +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/misc_utility.h b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/misc_utility.h new file mode 100644 index 0000000..1c356c0 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/misc_utility.h @@ -0,0 +1,28 @@ +#pragma once + +#include +typedef uintptr_t addr_t; + +#include +#include +#include + +#if defined(__LP64__) +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +// get macho segment by segment name +segment_command_t *macho_kit_get_segment_by_name(mach_header_t *mach_header, const char *segname); + +// get macho section by segment name and section name +section_t *macho_kit_get_section_by_name(mach_header_t *mach_header, const char *segname, const char *sectname); diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/sensitive_api_monitor.cc b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/sensitive_api_monitor.cc new file mode 100644 index 0000000..140de57 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/sensitive_api_monitor.cc @@ -0,0 +1,95 @@ +#include "dobby_internal.h" + +#include +#include +#include + +#include "SupervisorCallMonitor/supervisor_call_monitor.h" +#include "misc-helper/async_logger.h" + +#define PT_DENY_ATTACH 31 + +static void sensitive_api_handler(DobbyRegisterContext *ctx, const InterceptEntry *info) { + char buffer[256] = {0}; + int syscall_rum = ctx->general.regs.x16; + if (syscall_rum == 0) { + syscall_rum = (int)ctx->general.x[0]; + if (syscall_rum == SYS_ptrace) { + int request = ctx->general.x[1]; + if (request == PT_DENY_ATTACH) { + ctx->general.x[1] = 0; + // LOG(2, "syscall svc ptrace deny"); + } + } + if (syscall_rum == SYS_exit) { + // LOG(2, "syscall svc exit"); + } + } else if (syscall_rum > 0) { + if (syscall_rum == SYS_ptrace) { + int request = ctx->general.x[0]; + if (request == PT_DENY_ATTACH) { + ctx->general.x[0] = 0; + // LOG(2, "svc ptrace deny"); + } + } + if (syscall_rum == SYS_exit) { + // LOG(2, "svc exit"); + } + } + async_logger_print(buffer); +} + +static int get_func_svc_offset(addr_t func_addr) { + typedef int32_t arm64_instr_t; + for (int i = 0; i < 8; i++) { + arm64_instr_t *insn = (arm64_instr_t *)func_addr + i; + if (*insn == 0xd4001001) { + return i * sizeof(arm64_instr_t); + } + } + return 0; +} + +#include +__typeof(sysctl) *orig_sysctl; +int fake_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { + struct kinfo_proc *info = NULL; + int ret = orig_sysctl(name, namelen, oldp, oldlenp, newp, newlen); + if (name[0] == CTL_KERN && name[1] == KERN_PROC && name[2] == KERN_PROC_PID) { + info = (struct kinfo_proc *)oldp; + info->kp_proc.p_flag &= ~(P_TRACED); + } + return ret; +} + +void supervisor_call_monitor_register_sensitive_api_handler() { + char *sensitive_func_array[] = {"ptrace", "exit"}; + size_t count = sizeof(sensitive_func_array) / sizeof(char *); + for (size_t i = 0; i < count; i++) { + + addr_t func_addr = 0; + + char func_name[64] = {0}; + sprintf(func_name, "__%s", sensitive_func_array[i]); + func_addr = (addr_t)DobbySymbolResolver("libsystem_kernel.dylib", func_name); + if (func_addr == 0) { + func_addr = (addr_t)DobbySymbolResolver("libsystem_kernel.dylib", sensitive_func_array[i]); + } + if (func_addr == 0) { + LOG(2, "not found func %s", sensitive_func_array[i]); + continue; + } + int func_svc_offset = get_func_svc_offset(func_addr); + if (func_svc_offset == 0) { + LOG(2, "not found svc %s", sensitive_func_array[i]); + continue; + } + addr_t func_svc_addr = func_addr + func_svc_offset; + supervisor_call_monitor_register_svc(func_svc_addr); + } + + // =============== + DobbyHook((void *)sysctl, (void *)fake_sysctl, (void **)&orig_sysctl); + + supervisor_call_monitor_register_handler(sensitive_api_handler); +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/supervisor_call_monitor.cc b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/supervisor_call_monitor.cc new file mode 100644 index 0000000..762a2bb --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/supervisor_call_monitor.cc @@ -0,0 +1,138 @@ +#include "SupervisorCallMonitor/misc_utility.h" +#include "dobby_internal.h" +#include "PlatformUtil/ProcessRuntimeUtility.h" + +#include "misc-helper/async_logger.h" + +#include +std::vector *g_supervisor_call_handlers; + +static const char *fast_get_main_app_bundle_udid() { + static char *main_app_bundle_udid = NULL; + if (main_app_bundle_udid) + return main_app_bundle_udid; + + auto main = ProcessRuntimeUtility::GetProcessModuleMap()[0]; + char main_binary_path[2048] = {0}; + if (realpath(main.path, main_binary_path) == NULL) + return NULL; + + char *bundle_udid_ndx = main_binary_path + strlen("/private/var/containers/Bundle/Application/"); + main_app_bundle_udid = (char *)malloc(36 + 1); + strncpy(main_app_bundle_udid, bundle_udid_ndx, 36); + main_app_bundle_udid[36] = 0; + return main_app_bundle_udid; +} + +static void common_supervisor_call_monitor_handler(DobbyRegisterContext *ctx, const InterceptEntry *info) { + if (g_supervisor_call_handlers == NULL) { + return; + } + for (auto handler : *g_supervisor_call_handlers) { + handler(ctx, info); + } +} + +void supervisor_call_monitor_register_handler(DBICallTy handler) { + if (g_supervisor_call_handlers == NULL) { + g_supervisor_call_handlers = new std::vector(); + } + g_supervisor_call_handlers->push_back(handler); +} + +std::vector *g_svc_addr_array; + +void supervisor_call_monitor_register_svc(addr_t svc_addr) { + if (g_svc_addr_array == NULL) { + g_svc_addr_array = new std::vector(); + } + + if (g_svc_addr_array) { + auto iter = g_svc_addr_array->begin(); + for (; iter != g_svc_addr_array->end(); iter++) { + if (*iter == svc_addr) + return; + } + } + + g_svc_addr_array->push_back(svc_addr); + DobbyInstrument((void *)svc_addr, common_supervisor_call_monitor_handler); + DLOG(2, "register supervisor_call_monitor at %p", svc_addr); +} + +void supervisor_call_monitor_register_image(void *header) { + auto text_section = macho_kit_get_section_by_name((mach_header_t *)header, "__TEXT", "__text"); + + addr_t insn_addr = (addr_t)header + (addr_t)text_section->offset; + addr_t insn_addr_end = insn_addr + text_section->size; + + for (; insn_addr < insn_addr_end; insn_addr += sizeof(uint32_t)) { + if (*(uint32_t *)insn_addr == 0xd4001001) { + supervisor_call_monitor_register_svc((addr_t)insn_addr); + } + } +} + +void supervisor_call_monitor_register_main_app() { + const char *main_bundle_udid = fast_get_main_app_bundle_udid(); + auto module_map = ProcessRuntimeUtility::GetProcessModuleMap(); + for (auto module : module_map) { + if (strstr(module.path, main_bundle_udid)) { + LOG(2, "[supervisor_call_monitor] %s", module.path); + supervisor_call_monitor_register_image((void *)module.load_address); + } + } +} + +extern "C" int __shared_region_check_np(uint64_t *startaddress); + +struct dyld_cache_header *shared_cache_get_load_addr() { + static struct dyld_cache_header *shared_cache_load_addr = 0; + if (shared_cache_load_addr) + return shared_cache_load_addr; +#if 0 + if (syscall(294, &shared_cache_load_addr) == 0) { +#else + // FIXME: + if (__shared_region_check_np((uint64_t *)&shared_cache_load_addr) != 0) { +#endif + shared_cache_load_addr = 0; +} +return shared_cache_load_addr; +} +void supervisor_call_monitor_register_system_kernel() { + auto libsystem = ProcessRuntimeUtility::GetProcessModule("libsystem_kernel.dylib"); + addr_t libsystem_header = (addr_t)libsystem.load_address; + auto text_section = macho_kit_get_section_by_name((mach_header_t *)libsystem_header, "__TEXT", "__text"); + + addr_t shared_cache_load_addr = (addr_t)shared_cache_get_load_addr(); + addr_t insn_addr = shared_cache_load_addr + (addr_t)text_section->offset; + addr_t insn_addr_end = insn_addr + text_section->size; + + addr_t write_svc_addr = (addr_t)DobbySymbolResolver("libsystem_kernel.dylib", "write"); + write_svc_addr += 4; + + addr_t __psynch_mutexwait_svc_addr = (addr_t)DobbySymbolResolver("libsystem_kernel.dylib", "__psynch_mutexwait"); + __psynch_mutexwait_svc_addr += 4; + + for (; insn_addr < insn_addr_end; insn_addr += sizeof(uint32_t)) { + if (*(uint32_t *)insn_addr == 0xd4001001) { + if (insn_addr == write_svc_addr) + continue; + + if (insn_addr == __psynch_mutexwait_svc_addr) + continue; + supervisor_call_monitor_register_svc((addr_t)insn_addr); + } + } +} + +void supervisor_call_monitor_init() { + // create logger file + char logger_path[1024] = {0}; + sprintf(logger_path, "%s%s", getenv("HOME"), "/Documents/svc_monitor.txt"); + LOG(2, "HOME: %s", logger_path); + async_logger_init(logger_path); + + dobby_enable_near_branch_trampoline(); +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/supervisor_call_monitor.h b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/supervisor_call_monitor.h new file mode 100644 index 0000000..45bde0a --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/supervisor_call_monitor.h @@ -0,0 +1,24 @@ +#pragma once + +#include +typedef uintptr_t addr_t; + +#include "dobby.h" + +void supervisor_call_monitor_init(); + +void supervisor_call_monitor_register_handler(DBICallTy handler); + +void supervisor_call_monitor_register_svc(addr_t svc_addr); + +void supervisor_call_monitor_register_image(void *header); + +void supervisor_call_monitor_register_main_app(); + +void supervisor_call_monitor_register_system_kernel(); + +void supervisor_call_monitor_register_syscall_call_log_handler(); + +void supervisor_call_monitor_register_mach_syscall_call_log_handler(); + +void supervisor_call_monitor_register_sensitive_api_handler(); \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/system_call_log_handler.cc b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/system_call_log_handler.cc new file mode 100644 index 0000000..c78db6a --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/system_call_log_handler.cc @@ -0,0 +1,98 @@ +#include "dobby_internal.h" + +#include + +#include "misc-helper/async_logger.h" +#include "PlatformUtil/ProcessRuntimeUtility.h" +#include "SupervisorCallMonitor/misc_utility.h" +#include "SupervisorCallMonitor/supervisor_call_monitor.h" + +#include "XnuInternal/syscalls.c" + +static const char *syscall_num_to_str(int num) { + return syscallnames[num]; +} + +static addr_t getCallFirstArg(DobbyRegisterContext *ctx) { + addr_t result; +#if defined(_M_X64) || defined(__x86_64__) +#if defined(_WIN32) + result = ctx->general.regs.rcx; +#else + result = ctx->general.regs.rdi; +#endif +#elif defined(__arm64__) || defined(__aarch64__) + result = ctx->general.regs.x0; +#elif defined(__arm__) + result = ctx->general.regs.r0; +#else +#error "Not Support Architecture." +#endif + return result; +} + +static addr_t getRealLr(DobbyRegisterContext *ctx) { + addr_t closure_trampoline_reserved_stack = ctx->sp - sizeof(addr_t); + return *(addr_t *)closure_trampoline_reserved_stack; +} + +static addr_t fast_get_caller_from_main_binary(DobbyRegisterContext *ctx) { + static addr_t text_section_start = 0, text_section_end = 0; + static addr_t slide = 0; + if (text_section_start == 0 || text_section_end == 0) { + auto main = ProcessRuntimeUtility::GetProcessModule(""); + addr_t main_header = (addr_t)main.load_address; + + auto text_segment = macho_kit_get_segment_by_name((mach_header_t *)main_header, "__TEXT"); + slide = main_header - text_segment->vmaddr; + + auto text_section = macho_kit_get_section_by_name((mach_header_t *)main_header, "__TEXT", "__text"); + text_section_start = main_header + (addr_t)text_section->offset; + text_section_end = text_section_start + text_section->size; + } + + if (ctx == NULL) + return 0; + + addr_t lr = getRealLr(ctx); + if (lr > text_section_start && lr < text_section_end) + return lr - slide; + +#define MAX_STACK_ITERATE_LEVEL 8 + addr_t fp = ctx->fp; + if (fp == 0) + return 0; + for (int i = 0; i < MAX_STACK_ITERATE_LEVEL; i++) { + addr_t lr = *(addr_t *)(fp + sizeof(addr_t)); + if (lr > text_section_start && lr < text_section_end) + return lr - slide; + fp = *(addr_t *)fp; + if (fp == 0) + return 0; + } + return 0; +} + +static void syscall_log_handler(DobbyRegisterContext *ctx, const InterceptEntry *info) { + addr_t caller = fast_get_caller_from_main_binary(ctx); + if (caller == 0) + return; + + char buffer[2048] = {0}; + int syscall_rum = ctx->general.regs.x16; + if (syscall_rum == 0) { + syscall_rum = (int)getCallFirstArg(ctx); + sprintf(buffer, "[syscall svc-%d] %s\n", syscall_rum, syscall_num_to_str(syscall_rum)); + } else if (syscall_rum > 0) { + sprintf(buffer, "[svc-%d] %s\n", syscall_rum, syscall_num_to_str(syscall_rum)); + if (syscall_rum == 5) { + sprintf(buffer, "[svc-%d] %s:%s\n", syscall_rum, syscall_num_to_str(syscall_rum), (char *)ctx->general.regs.x0); + } + } + async_logger_print(buffer); +} + +void supervisor_call_monitor_register_syscall_call_log_handler() { + fast_get_caller_from_main_binary(NULL); + supervisor_call_monitor_register_handler(syscall_log_handler); +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/test_supervisor_call_monitor.cc b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/test_supervisor_call_monitor.cc new file mode 100644 index 0000000..862c4e1 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SupervisorCallMonitor/test_supervisor_call_monitor.cc @@ -0,0 +1,16 @@ + +#include "dobby_internal.h" + +#include "SupervisorCallMonitor/supervisor_call_monitor.h" + +#if 1 +__attribute__((constructor)) static void ctor() { + log_set_level(2); + log_switch_to_syslog(); + + supervisor_call_monitor_init(); + supervisor_call_monitor_register_main_app(); + supervisor_call_monitor_register_syscall_call_log_handler(); + supervisor_call_monitor_register_mach_syscall_call_log_handler(); +} +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/CMakeLists.txt b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/CMakeLists.txt new file mode 100644 index 0000000..0a0efe3 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/CMakeLists.txt @@ -0,0 +1,44 @@ +set(SOURCE_FILE_LIST ) + +if(NOT DEFINED DOBBY_DIR) + message(FATAL_ERROR "DOBBY_DIR must be set!") +endif() + +if(SYSTEM.Darwin AND (NOT BUILDING_KERNEL)) + set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST} + ${CMAKE_CURRENT_SOURCE_DIR}/macho/dyld_shared_cache_symbol_table_iterator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/macho/dobby_symbol_resolver.cc + + ${DOBBY_DIR}/source/Backend/UserMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc + ) +endif() +if(SYSTEM.Darwin AND BUILDING_KERNEL) + set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST} + ${CMAKE_CURRENT_SOURCE_DIR}/macho/dobby_symbol_resolver.cc + + ${DOBBY_DIR}/source/Backend/KernelMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc + ) +endif() +if(SYSTEM.Linux OR SYSTEM.Android) + set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST} + ${CMAKE_CURRENT_SOURCE_DIR}/elf/dobby_symbol_resolver.cc + + ${DOBBY_DIR}/source/Backend/UserMode/PlatformUtil/Linux/ProcessRuntimeUtility.cc + ) +endif() +if(SYSTEM.Windows) + set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST} + ${CMAKE_CURRENT_SOURCE_DIR}/pe/dobby_symbol_resolver.cc + + ${DOBBY_DIR}/source/Backend/UserMode/PlatformUtil/Windows/ProcessRuntimeUtility.cc + ) +endif() + +add_library(symbol_resolver + ${SOURCE_FILE_LIST} + ) + +include_directories( + . +) + diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/dobby_symbol_resolver.h b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/dobby_symbol_resolver.h new file mode 100644 index 0000000..22dee3c --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/dobby_symbol_resolver.h @@ -0,0 +1,15 @@ +#pragma once + +#if defined(BUILDING_INTERNAL) +#include "macho/dobby_symbol_resolver_priv.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void *DobbySymbolResolver(const char *image_name, const char *symbol_name); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/elf/dobby_symbol_resolver.cc b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/elf/dobby_symbol_resolver.cc new file mode 100644 index 0000000..75328cb --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/elf/dobby_symbol_resolver.cc @@ -0,0 +1,292 @@ +#include "SymbolResolver/dobby_symbol_resolver.h" +#include "common_header.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "PlatformUtil/ProcessRuntimeUtility.h" + +#include + +#undef LOG_TAG +#define LOG_TAG "DobbySymbolResolver" + +static void file_mmap(const char *file_path, uint8_t **data_ptr, size_t *data_size_ptr) { + uint8_t *mmap_data = NULL; + size_t file_size = 0; + + int fd = open(file_path, O_RDONLY, 0); + if (fd < 0) { + ERROR_LOG("%s open failed", file_path); + goto finished; + } + + { + struct stat s; + int rt = fstat(fd, &s); + if (rt != 0) { + ERROR_LOG("mmap failed"); + goto finished; + } + file_size = s.st_size; + } + + // auto align + mmap_data = (uint8_t *)mmap(0, file_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, fd, 0); + if (mmap_data == MAP_FAILED) { + ERROR_LOG("mmap failed"); + goto finished; + } + +finished: + close(fd); + + if (data_size_ptr) + *data_size_ptr = file_size; + if (data_ptr) + *data_ptr = mmap_data; +} + +static void file_unmap(void *data, size_t data_size) { + int ret = munmap(data, data_size); + if (ret != 0) { + ERROR_LOG("munmap failed"); + return; + } +} + +typedef struct elf_ctx { + void *header; + + uintptr_t load_bias; + + ElfW(Shdr) * sym_sh_; + ElfW(Shdr) * dynsym_sh_; + + const char *strtab_; + ElfW(Sym) * symtab_; + + const char *dynstrtab_; + ElfW(Sym) * dynsymtab_; + + size_t nbucket_; + size_t nchain_; + uint32_t *bucket_; + uint32_t *chain_; + + size_t gnu_nbucket_; + uint32_t *gnu_bucket_; + uint32_t *gnu_chain_; + uint32_t gnu_maskwords_; + uint32_t gnu_shift2_; + ElfW(Addr) * gnu_bloom_filter_; +} elf_ctx_t; + +static void get_syms(ElfW(Ehdr) * header, ElfW(Sym) * *symtab_ptr, char **strtab_ptr, int *count_ptr) { + ElfW(Shdr) *section_header = NULL; + section_header = (ElfW(Shdr) *)((addr_t)header + header->e_shoff); + + ElfW(Shdr) *section_strtab_section_header = NULL; + section_strtab_section_header = (ElfW(Shdr) *)((addr_t)section_header + header->e_shstrndx * header->e_shentsize); + char *section_strtab = NULL; + section_strtab = (char *)((addr_t)header + section_strtab_section_header->sh_offset); + + for (int i = 0; i < header->e_shnum; ++i) { + const char *section_name = (const char *)(section_strtab + section_header->sh_name); + if (section_header->sh_type == SHT_SYMTAB && strcmp(section_name, ".symtab") == 0) { + *symtab_ptr = (ElfW(Sym) *)((addr_t)header + section_header->sh_offset); + *count_ptr = section_header->sh_size / sizeof(ElfW(Sym)); + } + + if (section_header->sh_type == SHT_STRTAB && strcmp(section_name, ".strtab") == 0) { + *strtab_ptr = (char *)((addr_t)header + section_header->sh_offset); + } + section_header = (ElfW(Shdr) *)((addr_t)section_header + header->e_shentsize); + } +} + +int elf_ctx_init(elf_ctx_t *ctx, void *header_) { + ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)header_; + ctx->header = ehdr; + + ElfW(Addr) ehdr_addr = (ElfW(Addr))ehdr; + + // Handle dynamic segment + { + ElfW(Addr) addr = 0; + ElfW(Dyn) *dyn = NULL; + ElfW(Phdr) *phdr = reinterpret_cast(ehdr_addr + ehdr->e_phoff); + for (size_t i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_type == PT_DYNAMIC) { + dyn = reinterpret_cast(ehdr_addr + phdr[i].p_offset); + } else if (phdr[i].p_type == PT_LOAD) { + addr = ehdr_addr + phdr[i].p_offset - phdr[i].p_vaddr; + if (ctx->load_bias == 0) + ctx->load_bias = ehdr_addr - (phdr[i].p_vaddr - phdr[i].p_offset); + } else if (phdr[i].p_type == PT_PHDR) { + ctx->load_bias = (ElfW(Addr))phdr - phdr[i].p_vaddr; + } + } +// ctx->load_bias = +#if 0 + const char *strtab = nullptr; + ElfW(Sym) *symtab = nullptr; + for (ElfW(Dyn) *d = dyn; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_STRTAB) { + strtab = reinterpret_cast(addr + d->d_un.d_ptr); + } else if (d->d_tag == DT_SYMTAB) { + symtab = reinterpret_cast(addr + d->d_un.d_ptr); + } + } +#endif + } + + // Handle section + { + ElfW(Shdr) * dynsym_sh, *dynstr_sh; + ElfW(Shdr) * sym_sh, *str_sh; + + ElfW(Shdr) *shdr = reinterpret_cast(ehdr_addr + ehdr->e_shoff); + + ElfW(Shdr) *shstr_sh = NULL; + shstr_sh = &shdr[ehdr->e_shstrndx]; + char *shstrtab = NULL; + shstrtab = (char *)((addr_t)ehdr_addr + shstr_sh->sh_offset); + + for (size_t i = 0; i < ehdr->e_shnum; i++) { + if (shdr[i].sh_type == SHT_SYMTAB) { + sym_sh = &shdr[i]; + ctx->sym_sh_ = sym_sh; + ctx->symtab_ = (ElfW(Sym) *)(ehdr_addr + shdr[i].sh_offset); + } else if (shdr[i].sh_type == SHT_STRTAB && strcmp(shstrtab + shdr[i].sh_name, ".strtab") == 0) { + str_sh = &shdr[i]; + ctx->strtab_ = (const char *)(ehdr_addr + shdr[i].sh_offset); + } else if (shdr[i].sh_type == SHT_DYNSYM) { + dynsym_sh = &shdr[i]; + ctx->dynsym_sh_ = dynsym_sh; + ctx->dynsymtab_ = (ElfW(Sym) *)(ehdr_addr + shdr[i].sh_offset); + } else if (shdr[i].sh_type == SHT_STRTAB && strcmp(shstrtab + shdr[i].sh_name, ".dynstr") == 0) { + dynstr_sh = &shdr[i]; + ctx->dynstrtab_ = (const char *)(ehdr_addr + shdr[i].sh_offset); + } + } + } + + return 0; +} + +static void *iterate_symbol_table_impl(const char *symbol_name, ElfW(Sym) * symtab, const char *strtab, int count) { + for (int i = 0; i < count; ++i) { + ElfW(Sym) *sym = symtab + i; + const char *symbol_name_ = strtab + sym->st_name; + if (strcmp(symbol_name_, symbol_name) == 0) { + return (void *)sym->st_value; + } + } + return NULL; +} + +void *elf_ctx_iterate_symbol_table(elf_ctx_t *ctx, const char *symbol_name) { + void *result = NULL; + if (ctx->symtab_ && ctx->strtab_) { + size_t count = ctx->sym_sh_->sh_size / sizeof(ElfW(Sym)); + result = iterate_symbol_table_impl(symbol_name, ctx->symtab_, ctx->strtab_, count); + if (result) + return result; + } + + if (ctx->dynsymtab_ && ctx->dynstrtab_) { + size_t count = ctx->dynsym_sh_->sh_size / sizeof(ElfW(Sym)); + result = iterate_symbol_table_impl(symbol_name, ctx->dynsymtab_, ctx->dynstrtab_, count); + if (result) + return result; + } + return NULL; +} + +void *resolve_elf_internal_symbol(const char *library_name, const char *symbol_name) { + void *result = NULL; + + if (library_name) { + RuntimeModule module = ProcessRuntimeUtility::GetProcessModule(library_name); + + uint8_t *file_mem = NULL; + size_t file_mem_size = 0; + if (module.load_address) + file_mmap(module.path, &file_mem, &file_mem_size); + + elf_ctx_t ctx; + memset(&ctx, 0, sizeof(elf_ctx_t)); + if (file_mem) { + elf_ctx_init(&ctx, file_mem); + result = elf_ctx_iterate_symbol_table(&ctx, symbol_name); + } + + if (result) + result = (void *)((addr_t)result + (addr_t)module.load_address - ((addr_t)file_mem - (addr_t)ctx.load_bias)); + + if (file_mem) + file_unmap(file_mem, file_mem_size); + } + + if (!result) { + auto ProcessModuleMap = ProcessRuntimeUtility::GetProcessModuleMap(); + for (auto module : ProcessModuleMap) { + uint8_t *file_mem = NULL; + size_t file_mem_size = 0; + + if (module.load_address) + file_mmap(module.path, &file_mem, &file_mem_size); + + elf_ctx_t ctx; + memset(&ctx, 0, sizeof(elf_ctx_t)); + if (file_mem) { + elf_ctx_init(&ctx, file_mem); + result = elf_ctx_iterate_symbol_table(&ctx, symbol_name); + } + + if (result) + result = (void *)((addr_t)result + (addr_t)module.load_address - ((addr_t)file_mem - (addr_t)ctx.load_bias)); + + if (file_mem) + file_unmap(file_mem, file_mem_size); + + if (result) + break; + } + } + return result; +} + +// impl at "android_restriction.cc" +extern std::vector linker_get_solist(); + +PUBLIC void *DobbySymbolResolver(const char *image_name, const char *symbol_name_pattern) { + void *result = NULL; + +#if 0 + auto solist = linker_get_solist(); + for (auto soinfo : solist) { + uintptr_t handle = linker_soinfo_to_handle(soinfo); + if (image_name == NULL || strstr(linker_soinfo_get_realpath(soinfo), image_name) != 0) { + result = dlsym((void *)handle, symbol_name_pattern); + if (result) + return result; + } + } +#endif + result = dlsym(RTLD_DEFAULT, symbol_name_pattern); + if (result) + return result; + + result = resolve_elf_internal_symbol(image_name, symbol_name_pattern); + return result; +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dobby_symbol_resolver.cc b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dobby_symbol_resolver.cc new file mode 100644 index 0000000..3ea6b1e --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dobby_symbol_resolver.cc @@ -0,0 +1,454 @@ +#include "dobby_symbol_resolver.h" +#include "macho/dobby_symbol_resolver_priv.h" + +#include "common_header.h" + +#include +#include + +#include "PlatformUtil/ProcessRuntimeUtility.h" + +#if defined(BUILDING_KERNEL) +#else + +#include +#include +#include "SymbolResolver/macho/shared_cache_internal.h" + +#endif + +#undef LOG_TAG +#define LOG_TAG "DobbySymbolResolver" + +uintptr_t read_uleb128(const uint8_t **pp, const uint8_t *end) { + uint8_t *p = (uint8_t *) *pp; + uint64_t result = 0; + int bit = 0; + do { + if (p == end) + ASSERT(p == end); + + uint64_t slice = *p & 0x7f; + + if (bit > 63) + ASSERT(bit > 63); + else { + result |= (slice << bit); + bit += 7; + } + } while (*p++ & 0x80); + + *pp = p; + + return (uintptr_t) result; +} + +intptr_t read_sleb128(const uint8_t **pp, const uint8_t *end) { + uint8_t *p = (uint8_t *) *pp; + + int64_t result = 0; + int bit = 0; + uint8_t byte; + do { + if (p == end) + ASSERT(p == end); + byte = *p++; + result |= (((int64_t) (byte & 0x7f)) << bit); + bit += 7; + } while (byte & 0x80); + // sign extend negative numbers + if ((byte & 0x40) != 0) + result |= (~0ULL) << bit; + + *pp = p; + + return (intptr_t) result; +} + +// dyld +uint8_t *walk_exported_trie(const uint8_t *start, const uint8_t *end, const char *symbol) { + const uint8_t *p = start; + while (p != NULL) { + uintptr_t terminalSize = *p++; + if (terminalSize > 127) { + // except for re-export-with-rename, all terminal sizes fit in one byte + --p; + terminalSize = read_uleb128(&p, end); + } + if ((*symbol == '\0') && (terminalSize != 0)) { + //dyld::log("trieWalk(%p) returning %p\n", start, p); + return (uint8_t *) p; + } + const uint8_t *children = p + terminalSize; + if (children > end) { + // dyld::log("trieWalk() malformed trie node, terminalSize=0x%lx extends past end of trie\n", terminalSize); + return NULL; + } + //dyld::log("trieWalk(%p) sym=%s, terminalSize=%lu, children=%p\n", start, s, terminalSize, children); + uint8_t childrenRemaining = *children++; + p = children; + uintptr_t nodeOffset = 0; + for (; childrenRemaining > 0; --childrenRemaining) { + const char *ss = symbol; + //dyld::log("trieWalk(%p) child str=%s\n", start, (char*)p); + bool wrongEdge = false; + // scan whole edge to get to next edge + // if edge is longer than target symbol name, don't read past end of symbol name + char c = *p; + while (c != '\0') { + if (!wrongEdge) { + if (c != *ss) + wrongEdge = true; + ++ss; + } + ++p; + c = *p; + } + if (wrongEdge) { + // advance to next child + ++p; // skip over zero terminator + // skip over uleb128 until last byte is found + while ((*p & 0x80) != 0) + ++p; + ++p; // skip over last byte of uleb128 + if (p > end) { + // dyld::log("trieWalk() malformed trie node, child node extends past end of trie\n"); + return NULL; + } + } else { + // the symbol so far matches this edge (child) + // so advance to the child's node + ++p; + nodeOffset = read_uleb128(&p, end); + if ((nodeOffset == 0) || (&start[nodeOffset] > end)) { + // dyld::log("trieWalk() malformed trie child, nodeOffset=0x%lx out of range\n", nodeOffset); + return NULL; + } + symbol = ss; + //dyld::log("trieWalk() found matching edge advancing to node 0x%lx\n", nodeOffset); + break; + } + } + if (nodeOffset != 0) + p = &start[nodeOffset]; + else + p = NULL; + } + //dyld::log("trieWalk(%p) return NULL\n", start); + return NULL; +} + +uintptr_t iterate_exported_symbol(mach_header_t *header, const char *symbol_name, uint64_t *out_flags) { + segment_command_t *curr_seg_cmd; + struct dyld_info_command *dyld_info_cmd = nullptr; + struct linkedit_data_command *exports_trie_cmd = nullptr; + segment_command_t *text_segment = nullptr, *data_segment = nullptr, *linkedit_segment = nullptr; + + curr_seg_cmd = (segment_command_t *) ((uintptr_t) header + sizeof(mach_header_t)); + for (int i = 0; i < header->ncmds; i++) { + switch (curr_seg_cmd->cmd) { + case LC_SEGMENT_ARCH_DEPENDENT: { + if (strcmp(curr_seg_cmd->segname, "__LINKEDIT") == 0) { + linkedit_segment = curr_seg_cmd; + } else if (strcmp(curr_seg_cmd->segname, "__TEXT") == 0) { + text_segment = curr_seg_cmd; + } + } + break; + case LC_DYLD_EXPORTS_TRIE: { + exports_trie_cmd = (struct linkedit_data_command *) curr_seg_cmd; + } + break; + case LC_DYLD_INFO: + case LC_DYLD_INFO_ONLY: { + dyld_info_cmd = (struct dyld_info_command *) curr_seg_cmd; + } + break; + default: + break; + }; + curr_seg_cmd = (segment_command_t *) ((uintptr_t) curr_seg_cmd + curr_seg_cmd->cmdsize); + } + + if (text_segment == NULL || linkedit_segment == NULL) { + return 0; + } + + if (exports_trie_cmd == NULL && dyld_info_cmd == NULL) + return 0; + + uint32_t trieFileOffset = dyld_info_cmd ? dyld_info_cmd->export_off : exports_trie_cmd->dataoff; + uint32_t trieFileSize = dyld_info_cmd ? dyld_info_cmd->export_size : exports_trie_cmd->datasize; + + uintptr_t slide = (uintptr_t) header - (uintptr_t) text_segment->vmaddr; + uintptr_t linkedit_base = (uintptr_t) slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; + + void *exports = (void *) (linkedit_base + trieFileOffset); + if (exports == NULL) + return 0; + + uint8_t *exports_start = (uint8_t *) exports; + uint8_t *exports_end = exports_start + trieFileSize; + uint8_t *node = (uint8_t *) walk_exported_trie(exports_start, exports_end, symbol_name); + if (node == NULL) + return 0; + const uint8_t *p = node; + const uintptr_t flags = read_uleb128(&p, exports_end); + if (flags & EXPORT_SYMBOL_FLAGS_REEXPORT) { + return 0; + } + if (out_flags) + *out_flags = flags; + uint64_t trieValue = read_uleb128(&p, exports_end); + return trieValue; +#if 0 + if (off == (void *)0) { + if (symbol_name[0] != '_' && strlen(&symbol_name[1]) >= 1) { + char _symbol_name[1024] = {0}; + _symbol_name[0] = '_'; + strcpy(&_symbol_name[1], symbol_name); + off = (void *)walk_exported_trie((const uint8_t *)exports, (const uint8_t *)exports + trieFileSize, _symbol_name); + } + } +#endif +} + +void macho_ctx_init(macho_ctx_t *ctx, mach_header_t *header) { + ctx->header = header; + segment_command_t *curr_seg_cmd; + segment_command_t *text_segment = nullptr, *text_exec_segment = nullptr, *data_segment = nullptr, *data_const_segment = nullptr, + *linkedit_segment = nullptr; + struct symtab_command *symtab_cmd = nullptr; + struct dysymtab_command *dysymtab_cmd = nullptr; + struct dyld_info_command *dyld_info_cmd = nullptr; + + curr_seg_cmd = (segment_command_t *) ((uintptr_t) header + sizeof(mach_header_t)); + for (int i = 0; i < header->ncmds; i++) { + if (curr_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + // BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB and REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB + ctx->segments[ctx->segments_count++] = curr_seg_cmd; + + if (strcmp(curr_seg_cmd->segname, "__LINKEDIT") == 0) { + linkedit_segment = curr_seg_cmd; + } else if (strcmp(curr_seg_cmd->segname, "__DATA") == 0) { + data_segment = curr_seg_cmd; + } else if (strcmp(curr_seg_cmd->segname, "__DATA_CONST") == 0) { + data_const_segment = curr_seg_cmd; + } else if (strcmp(curr_seg_cmd->segname, "__TEXT") == 0) { + text_segment = curr_seg_cmd; + } else if (strcmp(curr_seg_cmd->segname, "__TEXT_EXEC") == 0) { + text_exec_segment = curr_seg_cmd; + } + } else if (curr_seg_cmd->cmd == LC_SYMTAB) { + symtab_cmd = (struct symtab_command *) curr_seg_cmd; + } else if (curr_seg_cmd->cmd == LC_DYSYMTAB) { + dysymtab_cmd = (struct dysymtab_command *) curr_seg_cmd; + } else if (curr_seg_cmd->cmd == LC_DYLD_INFO || curr_seg_cmd->cmd == LC_DYLD_INFO_ONLY) { + dyld_info_cmd = (struct dyld_info_command *) curr_seg_cmd; + } + curr_seg_cmd = (segment_command_t *) ((uintptr_t) curr_seg_cmd + curr_seg_cmd->cmdsize); + } + + uintptr_t slide = (uintptr_t) header - (uintptr_t) text_segment->vmaddr; + uintptr_t linkedit_base = (uintptr_t) slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; + + ctx->text_seg = text_segment; + ctx->text_exec_seg = text_exec_segment; + ctx->data_seg = data_segment; + ctx->data_const_seg = data_const_segment; + ctx->linkedit_seg = linkedit_segment; + + ctx->symtab_cmd = symtab_cmd; + ctx->dysymtab_cmd = dysymtab_cmd; + ctx->dyld_info_cmd = dyld_info_cmd; + + ctx->slide = slide; + ctx->linkedit_base = linkedit_base; + + ctx->symtab = (nlist_t *) (ctx->linkedit_base + ctx->symtab_cmd->symoff); + ctx->strtab = (char *) (ctx->linkedit_base + ctx->symtab_cmd->stroff); + ctx->indirect_symtab = (uint32_t *) (ctx->linkedit_base + ctx->dysymtab_cmd->indirectsymoff); +} + +uintptr_t iterate_symbol_table(char *name_pattern, nlist_t *symtab, uint32_t symtab_count, char *strtab) { + for (uint32_t i = 0; i < symtab_count; i++) { + if (symtab[i].n_value) { + uint32_t strtab_offset = symtab[i].n_un.n_strx; + char *symbol_name = strtab + strtab_offset; +#if 0 + LOG(1, "> %s", symbol_name); +#endif + if (strcmp(name_pattern, symbol_name) == 0) { + return symtab[i].n_value; + } + if (symbol_name[0] == '_') { + if (strcmp(name_pattern, &symbol_name[1]) == 0) { + return symtab[i].n_value; + } + } + } + } + return 0; +} + +static uintptr_t macho_kit_get_slide(mach_header_t *header) { + uintptr_t slide = 0; + + segment_command_t *curr_seg_cmd; + + curr_seg_cmd = (segment_command_t *) ((addr_t) header + sizeof(mach_header_t)); + for (int i = 0; i < header->ncmds; i++) { + if (curr_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(curr_seg_cmd->segname, "__TEXT") == 0) { + slide = (uintptr_t) header - curr_seg_cmd->vmaddr; + return slide; + } + } + curr_seg_cmd = (segment_command_t *) ((addr_t) curr_seg_cmd + curr_seg_cmd->cmdsize); + } + return 0; +} + +PUBLIC void *DobbyMachOSymbolResolverOptions(void *header_, const char *symbol_name, bool add_slide) { + mach_header_t *header = (mach_header_t *) header_; + uintptr_t result = 0; + + size_t slide = 0; + + if (add_slide) + slide = macho_kit_get_slide(header); + + // binary symbol table + macho_ctx_t macho_ctx; + memset(&macho_ctx, 0, sizeof(macho_ctx_t)); + macho_ctx_init(&macho_ctx, header); + result = iterate_symbol_table((char *) symbol_name, macho_ctx.symtab, macho_ctx.symtab_cmd->nsyms, macho_ctx.strtab); + if (result) { + result = result + slide; + return (void *) result; + } + return nullptr; +} + +PUBLIC void *DobbyMachOSymbolResolver(void *header_, const char *symbol_name) { + return DobbyMachOSymbolResolverOptions(header_, symbol_name, true); +} + +PUBLIC void *DobbySymbolResolver(const char *image_name, const char *symbol_name_pattern) { + uintptr_t result = 0; + + const std::vector modules = ProcessRuntimeUtility::GetProcessModuleMap(); + + for (auto iter = modules.begin(); iter != modules.end(); iter++) { + auto module = *iter; + // for (auto module : *modules) { + if (image_name != NULL && strnstr(module.path, image_name, strlen(module.path)) == NULL) + continue; + + mach_header_t *header = (mach_header_t *) module.load_address; + if (header == nullptr) + continue; + + size_t slide = 0; + if (header->magic == MH_MAGIC_64) + slide = macho_kit_get_slide(header); + +#if 0 + LOG(0, "resolve image: %s", module.path); +#endif + + nlist_t *symtab = NULL; + uint32_t symtab_count = 0; + char *strtab = NULL; + +#if !defined(BUILDING_KERNEL) +#if defined(__arm__) || defined(__aarch64__) + static int shared_cache_ctx_init_once = 0; + static shared_cache_ctx_t shared_cache_ctx; + if (shared_cache_ctx_init_once == 0) { + shared_cache_ctx_init_once = 1; + memset(&shared_cache_ctx, 0, sizeof(shared_cache_ctx_t)); + shared_cache_ctx_init(&shared_cache_ctx); + } + if (shared_cache_ctx.runtime_shared_cache) { + // shared cache library + if (shared_cache_is_contain(&shared_cache_ctx, (addr_t) header, 0)) { + shared_cache_get_symbol_table(&shared_cache_ctx, header, &symtab, &symtab_count, &strtab); + } + } + if (symtab && strtab) { + result = iterate_symbol_table((char *) symbol_name_pattern, symtab, symtab_count, strtab); + } + if (result) { + result = result + slide; + break; + } +#endif +#endif + + // binary symbol table + macho_ctx_t macho_ctx; + memset(&macho_ctx, 0, sizeof(macho_ctx_t)); + macho_ctx_init(&macho_ctx, header); + result = iterate_symbol_table((char *) symbol_name_pattern, macho_ctx.symtab, macho_ctx.symtab_cmd->nsyms, + macho_ctx.strtab); + if (result) { + result = result + slide; + break; + } + + // binary exported table(uleb128) + uint64_t flags; + result = iterate_exported_symbol((mach_header_t *) header, symbol_name_pattern, &flags); + if (result) { + switch (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) { + case EXPORT_SYMBOL_FLAGS_KIND_REGULAR: { + result += (uintptr_t) header; + } + break; + case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL: { + result += (uintptr_t) header; + } + break; + case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: { + } + break; + default: + break; + } + return (void *) result; + } + } + +#if !defined(BUILDING_KERNEL) + mach_header_t *dyld_header = NULL; + if (image_name != NULL && strcmp(image_name, "dyld") == 0) { + // task info + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t) &task_dyld_info, &count)) { + return NULL; + } + + // get dyld load address + const struct dyld_all_image_infos *infos = + (struct dyld_all_image_infos *) (uintptr_t) task_dyld_info.all_image_info_addr; + dyld_header = (mach_header_t *) infos->dyldImageLoadAddress; + + macho_ctx_t dyld_ctx; + memset(&dyld_ctx, 0, sizeof(macho_ctx_t)); + macho_ctx_init(&dyld_ctx, dyld_header); + result = + iterate_symbol_table((char *) symbol_name_pattern, dyld_ctx.symtab, dyld_ctx.symtab_cmd->nsyms, dyld_ctx.strtab); + if (result) { + result = result + (addr_t) dyld_header; + } + } +#endif + + if (result == 0) { + LOG(0, "symbol resolver failed: %s", symbol_name_pattern); + } + + return (void *) result; +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dobby_symbol_resolver_priv.h b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dobby_symbol_resolver_priv.h new file mode 100644 index 0000000..3d69448 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dobby_symbol_resolver_priv.h @@ -0,0 +1,46 @@ +#include +#include +#include + +#if defined(__LP64__) +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +typedef struct macho_ctx { + mach_header_t *header; + + uintptr_t slide; + uintptr_t linkedit_base; + + segment_command_t *segments[64]; + int segments_count; + + segment_command_t *text_seg; + segment_command_t *data_seg; + segment_command_t *text_exec_seg; + segment_command_t *data_const_seg; + segment_command_t *linkedit_seg; + + struct symtab_command *symtab_cmd; + struct dysymtab_command *dysymtab_cmd; + struct dyld_info_command *dyld_info_cmd; + + nlist_t *symtab; + char *strtab; + uint32_t *indirect_symtab; + +} macho_ctx_t; + +void macho_ctx_init(macho_ctx_t *ctx, mach_header_t *header); + +uintptr_t iterate_symbol_table(char *name_pattern, nlist_t *symtab, uint32_t symtab_count, char *strtab); diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dyld_shared_cache_symbol_table_iterator.cc b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dyld_shared_cache_symbol_table_iterator.cc new file mode 100644 index 0000000..d7f85fb --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/dyld_shared_cache_symbol_table_iterator.cc @@ -0,0 +1,241 @@ +#include +#include +#include +#include +#include + +#include // pthread_once +#include // mmap +#include // open + +#include "SymbolResolver/macho/shared_cache_internal.h" +#include "SymbolResolver/macho/shared-cache/dyld_cache_format.h" + +#include "logging/logging.h" + +#undef LOG_TAG +#define LOG_TAG "DobbySymbolResolverCache" + +#if 0 +extern "C" { +int __shared_region_check_np(uint64_t *startaddress); +} +#endif + +extern "C" const char *dyld_shared_cache_file_path(); + +static pthread_once_t mmap_dyld_shared_cache_once = PTHREAD_ONCE_INIT; + +extern "C" int __shared_region_check_np(uint64_t *startaddress); + +#include + +static char *fast_get_shared_cache_path() { +#if defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__x86_64__) + return NULL; +#endif + char *result = NULL; + char path_buffer[2048] = {0}; + + const char *path = NULL; + do { + path = dyld_shared_cache_file_path(); + if (path != NULL) { + break; + } else { + struct stat statbuf; + int r = 0; + + path = IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "arm64"; + r = stat(path, &statbuf); + if (r == 0) { + break; + } + path = IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "arm64e"; + r = stat(path, &statbuf); + if (r == 0) { + break; + } + path = MACOSX_MRM_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "arm64"; + r = stat(path, &statbuf); + if (r == 0) { + break; + } + path = MACOSX_MRM_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "arm64e"; + r = stat(path, &statbuf); + if (r == 0) { + break; + } + } + } while (0); + + if (path != NULL) { + strcpy(path_buffer, path); + result = (char *)malloc(strlen(path_buffer) + 1); + strcpy(result, path_buffer); + } + + return result; +} + +#include +#include +#include +struct dyld_cache_header *shared_cache_get_load_addr() { + static struct dyld_cache_header *shared_cache_load_addr = 0; + + // task info + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count)) { + return NULL; + } + + // get dyld load address + const struct dyld_all_image_infos *infos = + (struct dyld_all_image_infos *)(uintptr_t)task_dyld_info.all_image_info_addr; + shared_cache_load_addr = (struct dyld_cache_header *)infos->sharedCacheBaseAddress; + + return shared_cache_load_addr; + +#if 0 + if (shared_cache_load_addr) + return shared_cache_load_addr; +#if 0 + if (syscall(294, &shared_cache_load_addr) == 0) { +#else + if (__shared_region_check_np((uint64_t *)&shared_cache_load_addr) != 0) { +#endif + shared_cache_load_addr = 0; +} +#endif + return shared_cache_load_addr; +} + +int shared_cache_ctx_init(shared_cache_ctx_t *ctx) { + int fd; + const char *cache_file_path = NULL; + + cache_file_path = fast_get_shared_cache_path(); + if (cache_file_path == NULL) { + return -1; + } + + fd = open(cache_file_path, O_RDONLY, 0); + if (fd == -1) { + return KERN_FAILURE; + } + + struct dyld_cache_header *runtime_shared_cache; + struct dyld_cache_header *mmap_shared_cache; + + // auto align + runtime_shared_cache = shared_cache_get_load_addr(); + if (runtime_shared_cache == NULL) { + return KERN_FAILURE; + } + + // maybe shared cache is apple silicon + if (runtime_shared_cache->localSymbolsSize == 0) { + return KERN_FAILURE; + } + + size_t mmap_length = runtime_shared_cache->localSymbolsSize; + off_t mmap_offset = runtime_shared_cache->localSymbolsOffset; + mmap_shared_cache = + (struct dyld_cache_header *)mmap(0, mmap_length, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, mmap_offset); + if (mmap_shared_cache == MAP_FAILED) { + DLOG(0, "mmap shared cache failed"); + return KERN_FAILURE; + } + + // fake shared cache header + mmap_shared_cache = + (struct dyld_cache_header *)((addr_t)mmap_shared_cache - runtime_shared_cache->localSymbolsOffset); + + ctx->runtime_shared_cache = runtime_shared_cache; + ctx->mmap_shared_cache = mmap_shared_cache; + + // shared cache slide + const struct dyld_cache_mapping_info *mappings = + (struct dyld_cache_mapping_info *)((char *)runtime_shared_cache + runtime_shared_cache->mappingOffset); + uintptr_t slide = (uintptr_t)runtime_shared_cache - (uintptr_t)(mappings[0].address); + ctx->runtime_slide = slide; + + // shared cache symbol table + static struct dyld_cache_local_symbols_info *localInfo = NULL; + localInfo = + (struct dyld_cache_local_symbols_info *)((char *)mmap_shared_cache + runtime_shared_cache->localSymbolsOffset); + + static struct dyld_cache_local_symbols_entry *localEntries = NULL; + localEntries = (struct dyld_cache_local_symbols_entry *)((char *)localInfo + localInfo->entriesOffset); + + ctx->local_symbols_info = localInfo; + ctx->local_symbols_entries = localEntries; + + ctx->symtab = (nlist_t *)((char *)localInfo + localInfo->nlistOffset); + ctx->strtab = ((char *)localInfo) + localInfo->stringsOffset; + return 0; +} + +// refer: dyld +bool shared_cache_is_contain(shared_cache_ctx_t *ctx, addr_t addr, size_t length) { + struct dyld_cache_header *runtime_shared_cache; + if (ctx) { + runtime_shared_cache = ctx->runtime_shared_cache; + } else { + runtime_shared_cache = shared_cache_get_load_addr(); + } + + const struct dyld_cache_mapping_info *mappings = + (struct dyld_cache_mapping_info *)((char *)runtime_shared_cache + runtime_shared_cache->mappingOffset); + uintptr_t slide = (uintptr_t)runtime_shared_cache - (uintptr_t)(mappings[0].address); + uintptr_t unslidStart = (uintptr_t)addr - slide; + + // quick out if after end of cache + if (unslidStart > (mappings[2].address + mappings[2].size)) + return false; + + // walk cache regions + const struct dyld_cache_mapping_info *mappingsEnd = &mappings[runtime_shared_cache->mappingCount]; + uintptr_t unslidEnd = unslidStart + length; + for (const struct dyld_cache_mapping_info *m = mappings; m < mappingsEnd; ++m) { + if ((unslidStart >= m->address) && (unslidEnd < (m->address + m->size))) { + return true; + } + } + return false; +} + +int shared_cache_get_symbol_table(shared_cache_ctx_t *ctx, mach_header_t *image_header, nlist_t **out_symtab, + uint32_t *out_symtab_count, char **out_strtab) { + struct dyld_cache_header *runtime_shared_cache = NULL; + + runtime_shared_cache = ctx->runtime_shared_cache; + + uint64_t textOffsetInCache = (uint64_t)image_header - (uint64_t)runtime_shared_cache; + + nlist_t *localNlists = NULL; + uint32_t localNlistCount = 0; + const char *localStrings = NULL; + + const uint32_t entriesCount = ctx->local_symbols_info->entriesCount; + for (uint32_t i = 0; i < entriesCount; ++i) { + if (ctx->local_symbols_entries[i].dylibOffset == textOffsetInCache) { + uint32_t localNlistStart = ctx->local_symbols_entries[i].nlistStartIndex; + localNlistCount = ctx->local_symbols_entries[i].nlistCount; + localNlists = &ctx->symtab[localNlistStart]; + +#if 0 + static struct dyld_cache_image_info *imageInfos = NULL; + imageInfos = (struct dyld_cache_image_info *)((addr_t)g_mmap_shared_cache + g_mmap_shared_cache->imagesOffset); + char *image_name = (char *)g_mmap_shared_cache + imageInfos[i].pathFileOffset; + LOG(1, "dyld image: %s", image_name); +#endif + } + } + *out_symtab = localNlists; + *out_symtab_count = (uint32_t)localNlistCount; + *out_strtab = (char *)ctx->strtab; + return 0; +} diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/shared-cache/dyld_cache_format.h b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/shared-cache/dyld_cache_format.h new file mode 100644 index 0000000..29e046b --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/shared-cache/dyld_cache_format.h @@ -0,0 +1,530 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- +* +* Copyright (c) 2006-2015 Apple Inc. All rights reserved. +* +* @APPLE_LICENSE_HEADER_START@ +* +* This file contains Original Code and/or Modifications of Original Code +* as defined in and that are subject to the Apple Public Source License +* Version 2.0 (the 'License'). You may not use this file except in +* compliance with the License. Please obtain a copy of the License at +* http://www.opensource.apple.com/apsl/ and read it before using this +* file. +* +* The Original Code and all software distributed under the License are +* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +* Please see the License for the specific language governing rights and +* limitations under the License. +* +* @APPLE_LICENSE_HEADER_END@ +*/ +#ifndef __DYLD_CACHE_FORMAT__ +#define __DYLD_CACHE_FORMAT__ + +#include +#include +#include +#include + + +struct dyld_cache_header +{ + char magic[16]; // e.g. "dyld_v0 i386" + uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info + uint32_t mappingCount; // number of dyld_cache_mapping_info entries + uint32_t imagesOffset; // file offset to first dyld_cache_image_info + uint32_t imagesCount; // number of dyld_cache_image_info entries + uint64_t dyldBaseAddress; // base address of dyld when cache was built + uint64_t codeSignatureOffset; // file offset of code signature blob + uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file) + uint64_t slideInfoOffsetUnused; // unused. Used to be file offset of kernel slid info + uint64_t slideInfoSizeUnused; // unused. Used to be size of kernel slid info + uint64_t localSymbolsOffset; // file offset of where local symbols are stored + uint64_t localSymbolsSize; // size of local symbols information + uint8_t uuid[16]; // unique value for each shared cache file + uint64_t cacheType; // 0 for development, 1 for production + uint32_t branchPoolsOffset; // file offset to table of uint64_t pool addresses + uint32_t branchPoolsCount; // number of uint64_t entries + uint64_t accelerateInfoAddr; // (unslid) address of optimization info + uint64_t accelerateInfoSize; // size of optimization info + uint64_t imagesTextOffset; // file offset to first dyld_cache_image_text_info + uint64_t imagesTextCount; // number of dyld_cache_image_text_info entries + uint64_t patchInfoAddr; // (unslid) address of dyld_cache_patch_info + uint64_t patchInfoSize; // Size of all of the patch information pointed to via the dyld_cache_patch_info + uint64_t otherImageGroupAddrUnused; // unused + uint64_t otherImageGroupSizeUnused; // unused + uint64_t progClosuresAddr; // (unslid) address of list of program launch closures + uint64_t progClosuresSize; // size of list of program launch closures + uint64_t progClosuresTrieAddr; // (unslid) address of trie of indexes into program launch closures + uint64_t progClosuresTrieSize; // size of trie of indexes into program launch closures + uint32_t platform; // platform number (macOS=1, etc) + uint32_t formatVersion : 8, // dyld3::closure::kFormatVersion + dylibsExpectedOnDisk : 1, // dyld should expect the dylib exists on disk and to compare inode/mtime to see if cache is valid + simulator : 1, // for simulator of specified platform + locallyBuiltCache : 1, // 0 for B&I built cache, 1 for locally built cache + builtFromChainedFixups : 1, // some dylib in cache was built using chained fixups, so patch tables must be used for overrides + padding : 20; // TBD + uint64_t sharedRegionStart; // base load address of cache if not slid + uint64_t sharedRegionSize; // overall size of region cache can be mapped into + uint64_t maxSlide; // runtime slide of cache can be between zero and this value + uint64_t dylibsImageArrayAddr; // (unslid) address of ImageArray for dylibs in this cache + uint64_t dylibsImageArraySize; // size of ImageArray for dylibs in this cache + uint64_t dylibsTrieAddr; // (unslid) address of trie of indexes of all cached dylibs + uint64_t dylibsTrieSize; // size of trie of cached dylib paths + uint64_t otherImageArrayAddr; // (unslid) address of ImageArray for dylibs and bundles with dlopen closures + uint64_t otherImageArraySize; // size of ImageArray for dylibs and bundles with dlopen closures + uint64_t otherTrieAddr; // (unslid) address of trie of indexes of all dylibs and bundles with dlopen closures + uint64_t otherTrieSize; // size of trie of dylibs and bundles with dlopen closures + uint32_t mappingWithSlideOffset; // file offset to first dyld_cache_mapping_and_slide_info + uint32_t mappingWithSlideCount; // number of dyld_cache_mapping_and_slide_info entries +}; + +// Uncomment this and check the build errors for the current mapping offset to check against when adding new fields. +// template class A { int x[-size]; }; A a; + + +struct dyld_cache_mapping_info { + uint64_t address; + uint64_t size; + uint64_t fileOffset; + uint32_t maxProt; + uint32_t initProt; +}; + +// Contains the flags for the dyld_cache_mapping_and_slide_info flgs field +enum { + DYLD_CACHE_MAPPING_AUTH_DATA = 1 << 0U, + DYLD_CACHE_MAPPING_DIRTY_DATA = 1 << 1U, + DYLD_CACHE_MAPPING_CONST_DATA = 1 << 2U, +}; + +struct dyld_cache_mapping_and_slide_info { + uint64_t address; + uint64_t size; + uint64_t fileOffset; + uint64_t slideInfoFileOffset; + uint64_t slideInfoFileSize; + uint64_t flags; + uint32_t maxProt; + uint32_t initProt; +}; + +struct dyld_cache_image_info +{ + uint64_t address; + uint64_t modTime; + uint64_t inode; + uint32_t pathFileOffset; + uint32_t pad; +}; + +struct dyld_cache_image_info_extra +{ + uint64_t exportsTrieAddr; // address of trie in unslid cache + uint64_t weakBindingsAddr; + uint32_t exportsTrieSize; + uint32_t weakBindingsSize; + uint32_t dependentsStartArrayIndex; + uint32_t reExportsStartArrayIndex; +}; + + +struct dyld_cache_accelerator_info +{ + uint32_t version; // currently 1 + uint32_t imageExtrasCount; // does not include aliases + uint32_t imagesExtrasOffset; // offset into this chunk of first dyld_cache_image_info_extra + uint32_t bottomUpListOffset; // offset into this chunk to start of 16-bit array of sorted image indexes + uint32_t dylibTrieOffset; // offset into this chunk to start of trie containing all dylib paths + uint32_t dylibTrieSize; // size of trie containing all dylib paths + uint32_t initializersOffset; // offset into this chunk to start of initializers list + uint32_t initializersCount; // size of initializers list + uint32_t dofSectionsOffset; // offset into this chunk to start of DOF sections list + uint32_t dofSectionsCount; // size of initializers list + uint32_t reExportListOffset; // offset into this chunk to start of 16-bit array of re-exports + uint32_t reExportCount; // size of re-exports + uint32_t depListOffset; // offset into this chunk to start of 16-bit array of dependencies (0x8000 bit set if upward) + uint32_t depListCount; // size of dependencies + uint32_t rangeTableOffset; // offset into this chunk to start of ss + uint32_t rangeTableCount; // size of dependencies + uint64_t dyldSectionAddr; // address of libdyld's __dyld section in unslid cache +}; + +struct dyld_cache_accelerator_initializer +{ + uint32_t functionOffset; // address offset from start of cache mapping + uint32_t imageIndex; +}; + +struct dyld_cache_range_entry +{ + uint64_t startAddress; // unslid address of start of region + uint32_t size; + uint32_t imageIndex; +}; + +struct dyld_cache_accelerator_dof +{ + uint64_t sectionAddress; // unslid address of start of region + uint32_t sectionSize; + uint32_t imageIndex; +}; + +struct dyld_cache_image_text_info +{ + uuid_t uuid; + uint64_t loadAddress; // unslid address of start of __TEXT + uint32_t textSegmentSize; + uint32_t pathOffset; // offset from start of cache file +}; + + +// The rebasing info is to allow the kernel to lazily rebase DATA pages of the +// dyld shared cache. Rebasing is adding the slide to interior pointers. +struct dyld_cache_slide_info +{ + uint32_t version; // currently 1 + uint32_t toc_offset; + uint32_t toc_count; + uint32_t entries_offset; + uint32_t entries_count; + uint32_t entries_size; // currently 128 + // uint16_t toc[toc_count]; + // entrybitmap entries[entries_count]; +}; + +struct dyld_cache_slide_info_entry { + uint8_t bits[4096/(8*4)]; // 128-byte bitmap +}; + + +// The version 2 of the slide info uses a different compression scheme. Since +// only interior pointers (pointers that point within the cache) are rebased +// (slid), we know the possible range of the pointers and thus know there are +// unused bits in each pointer. We use those bits to form a linked list of +// locations needing rebasing in each page. +// +// Definitions: +// +// pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size +// pageStarts[] = info + info->page_starts_offset +// pageExtras[] = info + info->page_extras_offset +// valueMask = ~(info->delta_mask) +// deltaShift = __builtin_ctzll(info->delta_mask) - 2 +// +// There are three cases: +// +// 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE +// The page contains no values that need rebasing. +// +// 2) (pageStarts[pageIndex] & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA) == 0 +// All rebase locations are in one linked list. The offset of the first +// rebase location in the page is pageStarts[pageIndex] * 4. +// +// 3) pageStarts[pageIndex] & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA +// Multiple linked lists are needed for all rebase locations in a page. +// The pagesExtras array contains 2 or more entries each of which is the +// start of a new linked list in the page. The first is at: +// extrasStartIndex = (pageStarts[pageIndex] & 0x3FFF) +// The next is at extrasStartIndex+1. The last is denoted by +// having the high bit (DYLD_CACHE_SLIDE_PAGE_ATTR_END) of the pageExtras[] +// set. +// +// For 64-bit architectures, there is always enough free bits to encode all +// possible deltas. The info->delta_mask field shows where the delta is located +// in the pointer. That value must be masked off (valueMask) before the slide +// is added to the pointer. +// +// For 32-bit architectures, there are only three bits free (the three most +// significant bits). To extract the delta, you must first subtract value_add +// from the pointer value, then AND with delta_mask, then shift by deltaShift. +// That still leaves a maximum delta to the next rebase location of 28 bytes. +// To reduce the number or chains needed, an optimization was added. Turns +// out zero is common in the DATA region. A zero can be turned into a +// non-rebasing entry in the linked list. The can be done because nothing +// in the shared cache should point out of its dylib to the start of the shared +// cache. +// +// The code for processing a linked list (chain) is: +// +// uint32_t delta = 1; +// while ( delta != 0 ) { +// uint8_t* loc = pageStart + pageOffset; +// uintptr_t rawValue = *((uintptr_t*)loc); +// delta = ((rawValue & deltaMask) >> deltaShift); +// uintptr_t newValue = (rawValue & valueMask); +// if ( newValue != 0 ) { +// newValue += valueAdd; +// newValue += slideAmount; +// } +// *((uintptr_t*)loc) = newValue; +// pageOffset += delta; +// } +// +// +struct dyld_cache_slide_info2 +{ + uint32_t version; // currently 2 + uint32_t page_size; // currently 4096 (may also be 16384) + uint32_t page_starts_offset; + uint32_t page_starts_count; + uint32_t page_extras_offset; + uint32_t page_extras_count; + uint64_t delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location + uint64_t value_add; + //uint16_t page_starts[page_starts_count]; + //uint16_t page_extras[page_extras_count]; +}; +#define DYLD_CACHE_SLIDE_PAGE_ATTRS 0xC000 // high bits of uint16_t are flags +#define DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA 0x8000 // index is into extras array (not starts array) +#define DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE 0x4000 // page has no rebasing +#define DYLD_CACHE_SLIDE_PAGE_ATTR_END 0x8000 // last chain entry for page + + + +// The version 3 of the slide info uses a different compression scheme. Since +// only interior pointers (pointers that point within the cache) are rebased +// (slid), we know the possible range of the pointers and thus know there are +// unused bits in each pointer. We use those bits to form a linked list of +// locations needing rebasing in each page. +// +// Definitions: +// +// pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size +// pageStarts[] = info + info->page_starts_offset +// +// There are two cases: +// +// 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE +// The page contains no values that need rebasing. +// +// 2) otherwise... +// All rebase locations are in one linked list. The offset of the first +// rebase location in the page is pageStarts[pageIndex]. +// +// A pointer is one of of the variants in dyld_cache_slide_pointer3 +// +// The code for processing a linked list (chain) is: +// +// uint32_t delta = pageStarts[pageIndex]; +// dyld_cache_slide_pointer3* loc = pageStart; +// do { +// loc += delta; +// delta = loc->offsetToNextPointer; +// if ( loc->auth.authenticated ) { +// newValue = loc->offsetFromSharedCacheBase + results->slide + auth_value_add; +// newValue = sign_using_the_various_bits(newValue); +// } +// else { +// uint64_t value51 = loc->pointerValue; +// uint64_t top8Bits = value51 & 0x0007F80000000000ULL; +// uint64_t bottom43Bits = value51 & 0x000007FFFFFFFFFFULL; +// uint64_t targetValue = ( top8Bits << 13 ) | bottom43Bits; +// newValue = targetValue + results->slide; +// } +// loc->raw = newValue; +// } while (delta != 0); +// +// +struct dyld_cache_slide_info3 +{ + uint32_t version; // currently 3 + uint32_t page_size; // currently 4096 (may also be 16384) + uint32_t page_starts_count; + uint64_t auth_value_add; + uint16_t page_starts[/* page_starts_count */]; +}; + +#define DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE 0xFFFF // page has no rebasing + +union dyld_cache_slide_pointer3 +{ + uint64_t raw; + struct { + uint64_t pointerValue : 51, + offsetToNextPointer : 11, + unused : 2; + } plain; + + struct { + uint64_t offsetFromSharedCacheBase : 32, + diversityData : 16, + hasAddressDiversity : 1, + key : 2, + offsetToNextPointer : 11, + unused : 1, + authenticated : 1; // = 1; + } auth; +}; + + + +// The version 4 of the slide info is optimized for 32-bit caches up to 1GB. +// Since only interior pointers (pointers that point within the cache) are rebased +// (slid), we know the possible range of the pointers takes 30 bits. That +// gives us two bits to use to chain to the next rebase. +// +// Definitions: +// +// pageIndex = (pageAddress - startOfAllDataAddress)/info->page_size +// pageStarts[] = info + info->page_starts_offset +// pageExtras[] = info + info->page_extras_offset +// valueMask = ~(info->delta_mask) +// deltaShift = __builtin_ctzll(info->delta_mask) - 2 +// +// There are three cases: +// +// 1) pageStarts[pageIndex] == DYLD_CACHE_SLIDE4_PAGE_NO_REBASE +// The page contains no values that need rebasing. +// +// 2) (pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA) == 0 +// All rebase locations are in one linked list. The offset of the first +// rebase location in the page is pageStarts[pageIndex] * 4. +// +// 3) pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA +// Multiple chains are needed for all rebase locations in a page. +// The pagesExtras array contains 2 or more entries each of which is the +// start of a new chain in the page. The first is at: +// extrasStartIndex = (pageStarts[pageIndex] & DYLD_CACHE_SLIDE4_PAGE_INDEX) +// The next is at extrasStartIndex+1. The last is denoted by +// having the high bit (DYLD_CACHE_SLIDE4_PAGE_EXTRA_END) of the pageExtras[]. +// +// For 32-bit architectures, there are only two bits free (the two most +// significant bits). To extract the delta, you must first subtract value_add +// from the pointer value, then AND with delta_mask, then shift by deltaShift. +// That still leaves a maximum delta to the next rebase location of 12 bytes. +// To reduce the number or chains needed, an optimization was added. Turns +// most of the non-rebased data are small values and can be co-opt'ed into +// being used in the chain. The can be done because nothing +// in the shared cache should point to the first 64KB which are in the shared +// cache header information. So if the resulting pointer points to the +// start of the cache +/-32KB, then it is actually a small number that should +// not be rebased, but just reconstituted. +// +// The code for processing a linked list (chain) is: +// +// uint32_t delta = 1; +// while ( delta != 0 ) { +// uint8_t* loc = pageStart + pageOffset; +// uint32_t rawValue = *((uint32_t*)loc); +// delta = ((rawValue & deltaMask) >> deltaShift); +// uintptr_t newValue = (rawValue & valueMask); +// if ( (newValue & 0xFFFF8000) == 0 ) { +// // small positive non-pointer, use as-is +// } +// else if ( (newValue & 0x3FFF8000) == 0x3FFF8000 ) { +// // small negative non-pointer +// newValue |= 0xC0000000; +// } +// else { +// // pointer that needs rebasing +// newValue += valueAdd; +// newValue += slideAmount; +// } +// *((uint32_t*)loc) = newValue; +// pageOffset += delta; +// } +// +// +struct dyld_cache_slide_info4 +{ + uint32_t version; // currently 4 + uint32_t page_size; // currently 4096 (may also be 16384) + uint32_t page_starts_offset; + uint32_t page_starts_count; + uint32_t page_extras_offset; + uint32_t page_extras_count; + uint64_t delta_mask; // which (contiguous) set of bits contains the delta to the next rebase location (0xC0000000) + uint64_t value_add; // base address of cache + //uint16_t page_starts[page_starts_count]; + //uint16_t page_extras[page_extras_count]; +}; +#define DYLD_CACHE_SLIDE4_PAGE_NO_REBASE 0xFFFF // page has no rebasing +#define DYLD_CACHE_SLIDE4_PAGE_INDEX 0x7FFF // mask of page_starts[] values +#define DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA 0x8000 // index is into extras array (not a chain start offset) +#define DYLD_CACHE_SLIDE4_PAGE_EXTRA_END 0x8000 // last chain entry for page + + + + +struct dyld_cache_local_symbols_info +{ + uint32_t nlistOffset; // offset into this chunk of nlist entries + uint32_t nlistCount; // count of nlist entries + uint32_t stringsOffset; // offset into this chunk of string pool + uint32_t stringsSize; // byte count of string pool + uint32_t entriesOffset; // offset into this chunk of array of dyld_cache_local_symbols_entry + uint32_t entriesCount; // number of elements in dyld_cache_local_symbols_entry array +}; + +struct dyld_cache_local_symbols_entry +{ + uint32_t dylibOffset; // offset in cache file of start of dylib + uint32_t nlistStartIndex; // start index of locals for this dylib + uint32_t nlistCount; // number of local symbols for this dylib +}; + +struct dyld_cache_patch_info +{ + uint64_t patchTableArrayAddr; // (unslid) address of array for dyld_cache_image_patches for each image + uint64_t patchTableArrayCount; // count of patch table entries + uint64_t patchExportArrayAddr; // (unslid) address of array for patch exports for each image + uint64_t patchExportArrayCount; // count of patch exports entries + uint64_t patchLocationArrayAddr; // (unslid) address of array for patch locations for each patch + uint64_t patchLocationArrayCount;// count of patch location entries + uint64_t patchExportNamesAddr; // blob of strings of export names for patches + uint64_t patchExportNamesSize; // size of string blob of export names for patches +}; + +struct dyld_cache_image_patches +{ + uint32_t patchExportsStartIndex; + uint32_t patchExportsCount; +}; + +struct dyld_cache_patchable_export +{ + uint32_t cacheOffsetOfImpl; + uint32_t patchLocationsStartIndex; + uint32_t patchLocationsCount; + uint32_t exportNameOffset; +}; + +struct dyld_cache_patchable_location +{ + uint64_t cacheOffset : 32, + high7 : 7, + addend : 5, // 0..31 + authenticated : 1, + usesAddressDiversity : 1, + key : 2, + discriminator : 16; +}; + + +// This is the location of the macOS shared cache on macOS 11.0 and later +#define MACOSX_MRM_DYLD_SHARED_CACHE_DIR "/System/Library/dyld/" + +// This is old define for the old location of the dyld cache +#define MACOSX_DYLD_SHARED_CACHE_DIR MACOSX_MRM_DYLD_SHARED_CACHE_DIR + +#define IPHONE_DYLD_SHARED_CACHE_DIR "/System/Library/Caches/com.apple.dyld/" +#if !TARGET_OS_SIMULATOR +#define DYLD_SHARED_CACHE_BASE_NAME "dyld_shared_cache_" +#else +#define DYLD_SHARED_CACHE_BASE_NAME "dyld_sim_shared_cache_" +#endif +#define DYLD_SHARED_CACHE_DEVELOPMENT_EXT ".development" + +static const uint64_t kDyldSharedCacheTypeDevelopment = 0; +static const uint64_t kDyldSharedCacheTypeProduction = 1; + + + + +#endif // __DYLD_CACHE_FORMAT__ + + diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/shared_cache_internal.h b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/shared_cache_internal.h new file mode 100644 index 0000000..9facadf --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/macho/shared_cache_internal.h @@ -0,0 +1,70 @@ +#include +#include +#include + +#if defined(__LP64__) +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +#if __i386__ +#define ARCH_NAME "i386" +#define ARCH_CACHE_MAGIC "dyld_v1 i386" +#elif __x86_64__ +#define ARCH_NAME "x86_64" +#define ARCH_CACHE_MAGIC "dyld_v1 x86_64" +#define ARCH_NAME_H "x86_64h" +#define ARCH_CACHE_MAGIC_H "dyld_v1 x86_64h" +#elif __ARM_ARCH_7K__ +#define ARCH_NAME "armv7k" +#define ARCH_CACHE_MAGIC "dyld_v1 armv7k" +#elif __ARM_ARCH_7A__ +#define ARCH_NAME "armv7" +#define ARCH_CACHE_MAGIC "dyld_v1 armv7" +#elif __ARM_ARCH_7S__ +#define ARCH_NAME "armv7s" +#define ARCH_CACHE_MAGIC "dyld_v1 armv7s" +#elif __arm64e__ +#define ARCH_NAME "arm64e" +#define ARCH_CACHE_MAGIC "dyld_v1 arm64e" +#elif __arm64__ +#if __LP64__ +#define ARCH_NAME "arm64" +#define ARCH_CACHE_MAGIC "dyld_v1 arm64" +#else +#define ARCH_NAME "arm64_32" +#define ARCH_CACHE_MAGIC "dyld_v1arm64_32" +#endif +#endif + +typedef uintptr_t addr_t; + +typedef struct shared_cache_ctx { + struct dyld_cache_header *runtime_shared_cache; + struct dyld_cache_header *mmap_shared_cache; + + uintptr_t runtime_slide; + + struct dyld_cache_local_symbols_info *local_symbols_info; + struct dyld_cache_local_symbols_entry *local_symbols_entries; + + nlist_t *symtab; + char *strtab; + +} shared_cache_ctx_t; + +int shared_cache_ctx_init(shared_cache_ctx_t *ctx); + +bool shared_cache_is_contain(shared_cache_ctx_t *ctx, addr_t addr, size_t length); + +int shared_cache_get_symbol_table(shared_cache_ctx_t *ctx, mach_header_t *image_header, nlist_t **out_symtab, + uint32_t *out_symtab_count, char **out_strtab); diff --git a/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/pe/dobby_symbol_resolver.cc b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/pe/dobby_symbol_resolver.cc new file mode 100644 index 0000000..65920a0 --- /dev/null +++ b/app/src/main/cpp/Dobby/builtin-plugin/SymbolResolver/pe/dobby_symbol_resolver.cc @@ -0,0 +1,26 @@ +#include "SymbolResolver/dobby_symbol_resolver.h" +#include "common_header.h" + +#include + +#include +#include + +#include "PlatformUtil/ProcessRuntimeUtility.h" + +#include + +#undef LOG_TAG +#define LOG_TAG "DobbySymbolResolver" + +PUBLIC void *DobbySymbolResolver(const char *image_name, const char *symbol_name_pattern) { + void *result = NULL; + + HMODULE hMod = LoadLibraryExA(image_name, NULL, DONT_RESOLVE_DLL_REFERENCES); + result = GetProcAddress(hMod, symbol_name_pattern); + if (result) + return result; + + //result = resolve_elf_internal_symbol(image_name, symbol_name_pattern); + return result; +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/cmake/Macros.cmake b/app/src/main/cpp/Dobby/cmake/Macros.cmake new file mode 100644 index 0000000..5774bef --- /dev/null +++ b/app/src/main/cpp/Dobby/cmake/Macros.cmake @@ -0,0 +1,3 @@ +macro(SET_OPTION option value) + set(${option} ${value} CACHE INTERNAL "" FORCE) +endmacro() \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/cmake/Util.cmake b/app/src/main/cpp/Dobby/cmake/Util.cmake new file mode 100644 index 0000000..6a722a2 --- /dev/null +++ b/app/src/main/cpp/Dobby/cmake/Util.cmake @@ -0,0 +1,19 @@ +# Check files list exist +function(check_files_exist CHECK_FILES) + foreach(file ${CHECK_FILES}) + if(NOT EXISTS "${file}") + message(FATAL_ERROR "${file} NOT EXISTS!") + endif() + endforeach() +endfunction(check_files_exist CHECK_FILES) + +# Search suffix files +function(search_suffix_files suffix INPUT_VARIABLE OUTPUT_VARIABLE) + set(ResultFiles ) + foreach(filePath ${${INPUT_VARIABLE}}) + # message(STATUS "[*] searching *.${suffix} from ${filePath}") + file(GLOB files ${filePath}/*.${suffix}) + set(ResultFiles ${ResultFiles} ${files}) + endforeach() + set(${OUTPUT_VARIABLE} ${ResultFiles} PARENT_SCOPE) +endfunction() diff --git a/app/src/main/cpp/Dobby/cmake/auto_source_group.cmake b/app/src/main/cpp/Dobby/cmake/auto_source_group.cmake new file mode 100644 index 0000000..f563836 --- /dev/null +++ b/app/src/main/cpp/Dobby/cmake/auto_source_group.cmake @@ -0,0 +1,32 @@ +function (auto_source_group _folder _base _pattern) + if (ARGC GREATER 3) + set(_exclude ${ARGN}) + else () + set(_exclude) + endif () + file (GLOB _files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/ ${_folder}/*) + set (folder_files) + foreach (_fname ${_files}) + if (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_fname}) + auto_source_group ("${_fname}" "${_base}" "${_pattern}" "${_exclude}") + elseif (_fname MATCHES ${_pattern}) + if(_exclude) + if (NOT _fname MATCHES ${_exclude}) + set(folder_files ${folder_files} ${_fname}) + endif () + else () + set(folder_files ${folder_files} ${_fname}) + endif () + endif () + endforeach () + + string(REPLACE "./" "" _folder2 ${_folder}) + string(REPLACE "/" "\\" _folder2 ${_folder2}) + if (_folder2 STREQUAL ".") + source_group(${_base} FILES ${folder_files}) + else () + source_group(${_base}\\${_folder2} FILES ${folder_files}) + endif () + + set(AUTO_FILES_RESULT ${AUTO_FILES_RESULT} ${folder_files} PARENT_SCOPE) +endfunction () \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/cmake/build_environment_check.cmake b/app/src/main/cpp/Dobby/cmake/build_environment_check.cmake new file mode 100644 index 0000000..9e7a67f --- /dev/null +++ b/app/src/main/cpp/Dobby/cmake/build_environment_check.cmake @@ -0,0 +1,86 @@ +if(__BUILD_ENVIRONMENT_CHECK) + return() +endif() +set(__BUILD_ENVIRONMENT_CHECK TRUE) + +message(STATUS "") +message(STATUS "********* build environment check ***********") + + +# The Compiler ID +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + set(COMPILER.Clang 1) +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(COMPILER.Gcc 1) +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(COMPILER.MSVC 1) +else() + message (FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER_ID} not configured") +endif() +message(STATUS "\tCompiler: \t ${CMAKE_CXX_COMPILER_ID}") + +if(MSVC) + string(TOLOWER ${MSVC_CXX_ARCHITECTURE_ID} CMAKE_SYSTEM_PROCESSOR) + set(CMAKE_SYSTEM_PROCESSOR ${MSVC_CXX_ARCHITECTURE_ID}) +endif() + + +if(BUILDING_SILICON) + set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_OSX_ARCHITECTURES}) +endif() + +string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} CMAKE_SYSTEM_PROCESSOR) + +# The Processor +if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*|x64.*") + set(PROCESSOR.X86_64 1) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686.*|i386.*|x86.*|amd64.*|AMD64.*") + set(PROCESSOR.X86 1) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm64.*") + set(PROCESSOR.AARCH64 1) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)") + set(PROCESSOR.AARCH64 1) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)") + set(PROCESSOR.ARM 1) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64le") + message(STATUS "NOT SUPPORT ${CMAKE_SYSTEM_PROCESSOR}") + set(PROCESSOR.PPC64LE 1) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64") + message(STATUS "NOT SUPPORT ${CMAKE_SYSTEM_PROCESSOR}") + set(PROCESSOR.PPC64 1) +else() + message (FATAL_ERROR "Processor ${CMAKE_SYSTEM_PROCESSOR} not configured") +endif() +message(STATUS "\tProcessor:\t ${CMAKE_SYSTEM_PROCESSOR}") + +# The System +if(CMAKE_SYSTEM_NAME MATCHES "^Android") + set(SYSTEM.Android 1) +elseif(CMAKE_SYSTEM_NAME MATCHES "^Windows") + set(SYSTEM.Windows 1) +elseif(CMAKE_SYSTEM_NAME MATCHES "^Linux") + set(SYSTEM.Linux 1) +elseif(CMAKE_SYSTEM_NAME MATCHES "^iOS") + set(SYSTEM.iOS 1) + set(SYSTEM.Darwin 1) +elseif(CMAKE_SYSTEM_NAME MATCHES "^macOS") + set(SYSTEM.macOS 1) + set(SYSTEM.Darwin 1) +elseif(CMAKE_SYSTEM_NAME MATCHES "^Darwin") + if(PROCESSOR.AARCH64 OR PROCESSOR.ARM) + set(CMAKE_SYSTEM_NAME "iOS or Silicon") + set(SYSTEM.iOS 1) + set(SYSTEM.Silicon 1) + elseif(PROCESSOR.X86 OR PROCESSOR.X86_64) + set(CMAKE_SYSTEM_NAME "macOS") + set(SYSTEM.macOS 1) + endif() + set(SYSTEM.Darwin 1) +else() + message (FATAL_ERROR "System ${CMAKE_SYSTEM_NAME} not configured") +endif() +message(STATUS "\tSystem: \t ${CMAKE_SYSTEM_NAME}") + +message(STATUS "***************************************") +message(STATUS "") diff --git a/app/src/main/cpp/Dobby/cmake/compiler_and_linker.cmake b/app/src/main/cpp/Dobby/cmake/compiler_and_linker.cmake new file mode 100644 index 0000000..b45a229 --- /dev/null +++ b/app/src/main/cpp/Dobby/cmake/compiler_and_linker.cmake @@ -0,0 +1,53 @@ +# :< You Shall Not Pass! +if (0) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror") +endif () + +set(linker_flags "") +if (NOT DOBBY_DEBUG) + set(linker_flags "${linker_flags} -Wl,-x -Wl,-S") +endif () + +if (SYSTEM.Darwin) + # set(compiler_flags "${compiler_flags} -nostdinc++") +elseif (SYSTEM.Android) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer") + if (NOT DOBBY_DEBUG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") + set(linker_flags "${linker_flags} -Wl,--gc-sections -Wl,--exclude-libs,ALL") + endif () +elseif (SYSTEM.Linux) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + if (COMPILER.Clang) + if (PROCESSOR.ARM) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=armv7-unknown-linux-gnueabihf") + elseif (PROCESSOR.ARM64) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=aarch64-unknown-linux-gnu") + elseif (PROCESSOR.X86) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=i686-unknown-linux-gnu") + elseif (PROCESSOR.X86_64) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=x86_64-unknown-linux-gnu") + endif () + endif () +elseif (SYSTEM.Windows) +endif () + +if (NOT DOBBY_DEBUG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden") +endif () + +if (PROCESSOR.ARM) + set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch armv7 -x assembler-with-cpp") +elseif (PROCESSOR.AARCH64) + set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch arm64 -x assembler-with-cpp") +endif () + +# sync cxx with c flags +# set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}") + +message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}") +message(STATUS "CMAKE_CXX_COMPILER: ${CMAKE_CXX_COMPILER}") +message(STATUS "CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") +message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") +message(STATUS "CMAKE_SHARED_LINKER_FLAGS: ${CMAKE_SHARED_LINKER_FLAGS}") diff --git a/app/src/main/cpp/Dobby/cmake/dobby.xcode.source.cmake b/app/src/main/cpp/Dobby/cmake/dobby.xcode.source.cmake new file mode 100644 index 0000000..64fb0e0 --- /dev/null +++ b/app/src/main/cpp/Dobby/cmake/dobby.xcode.source.cmake @@ -0,0 +1,94 @@ +set(dobby.SOURCE_FILE_LIST + # cpu + source/core/arch/CpuFeature.cc + source/core/arch/CpuRegister.cc + + # cpu - x86 + source/core/arch/x86/cpu-x86.cc + + # assembler + source/core/assembler/assembler.cc + source/core/assembler/assembler-arm.cc + source/core/assembler/assembler-arm64.cc + source/core/assembler/assembler-ia32.cc + source/core/assembler/assembler-x64.cc + + # codegen + source/core/codegen/codegen-arm.cc + source/core/codegen/codegen-arm64.cc + source/core/codegen/codegen-ia32.cc + source/core/codegen/codegen-x64.cc + + # executable memory - code buffer + source/MemoryAllocator/CodeBuffer/CodeBufferBase.cc + source/MemoryAllocator/CodeBuffer/code-buffer-x86.cc + + # executable memory + source/MemoryAllocator/AssemblyCodeBuilder.cc + source/MemoryAllocator/MemoryArena.cc + + # instruction relocation + source/InstructionRelocation/arm/InstructionRelocationARM.cc + source/InstructionRelocation/arm64/InstructionRelocationARM64.cc + source/InstructionRelocation/x86/X86InstructionRelocation.cc + source/InstructionRelocation/x64/InstructionRelocationX64.cc + + source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.c + + # intercept routing + source/InterceptRouting/InterceptRouting.cpp + + # intercept routing trampoline + source/TrampolineBridge/Trampoline/arm/trampoline-arm.cc + source/TrampolineBridge/Trampoline/arm64/trampoline-arm64.cc + source/TrampolineBridge/Trampoline/x86/trampoline-x86.cc + source/TrampolineBridge/Trampoline/x64/trampoline-x64.cc + + # intercept routing plugin (buildin) + source/InterceptRouting/Routing/FunctionInlineReplace/function-inline-replace.cc + source/InterceptRouting/Routing/FunctionInlineReplace/FunctionInlineReplaceExport.cc + + # plugin register + source/InterceptRouting/RoutingPlugin/RoutingPlugin.cc + + # unified interface + + # platform util + source/UserMode/PlatformUtil/${platform2}/ProcessRuntimeUtility.cc + + # user mode - platform interface + source/UserMode/UnifiedInterface/platform-${platform1}.cc + + # user mode - executable memory + source/UserMode/ExecMemory/code-patch-tool-${platform1}.cc + source/UserMode/ExecMemory/clear-cache-tool-all.c + + # main + source/dobby.cpp + source/Interceptor.cpp + source/InterceptEntry.cpp + ) + +if(FunctionWrapper OR DynamicBinaryInstrument) + set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST} + # closure trampoline bridge + source/TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.cc + + source/TrampolineBridge/ClosureTrampolineBridge/arm/helper-arm.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm/closure-bridge-arm.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm/ClosureTrampolineARM.cc + + source/TrampolineBridge/ClosureTrampolineBridge/arm64/helper-arm64.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm64/closure-bridge-arm64.cc + source/TrampolineBridge/ClosureTrampolineBridge/arm64/ClosureTrampolineARM64.cc + + source/TrampolineBridge/ClosureTrampolineBridge/x64/helper-x64.cc + source/TrampolineBridge/ClosureTrampolineBridge/x64/closure-bridge-x64.cc + source/TrampolineBridge/ClosureTrampolineBridge/x64/ClosureTrampolineX64.cc + + # user mode - multi thread support + source/UserMode/MultiThreadSupport/ThreadSupport.cpp + source/UserMode/Thread/PlatformThread.cc + source/UserMode/Thread/platform-thread-${platform1}.cc + ) +endif() \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/cmake/platform/platform-darwin.cmake b/app/src/main/cpp/Dobby/cmake/platform/platform-darwin.cmake new file mode 100644 index 0000000..4ea0af6 --- /dev/null +++ b/app/src/main/cpp/Dobby/cmake/platform/platform-darwin.cmake @@ -0,0 +1,30 @@ +# set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR TRUE) +set(CMAKE_INSTALL_NAME_DIR "@rpath") +set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,") +add_library(DobbyX ${DOBBY_LIBRARY_TYPE} ${dobby.HEADER_FILE_LIST} ${dobby.SOURCE_FILE_LIST} ${logging.SOURCE_FILE_LIST} ${misc_helper.SOURCE_FILE_LIST} ${dobby.plugin.SOURCE_FILE_LIST}) + +set_target_properties(DobbyX + PROPERTIES + LINK_FLAGS "${linker_flags}" + COMPILE_FLAGS "${compiler_flags}" + ) + +# set framework property +set_target_properties(DobbyX PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION A + MACOSX_FRAMEWORK_IDENTIFIER "com.dobby.dobby" + # MACOSX_FRAMEWORK_INFO_PLIST Info.plist + VERSION 1.0.0 # current version + SOVERSION 1.0.0 # compatibility version + PUBLIC_HEADER include/dobby.h + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development" + ) + +if ((SYSTEM.Darwin AND BUILDING_PLUGIN) AND (NOT BUILDING_KERNEL)) +add_subdirectory(builtin-plugin/Dyld2HideLibrary) +add_subdirectory(builtin-plugin/ObjcRuntimeHook) +if (PROCESSOR.AARCH64) + add_subdirectory(builtin-plugin/SupervisorCallMonitor) +endif () +endif() \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/cmake/xcode_generator_helper.cmake b/app/src/main/cpp/Dobby/cmake/xcode_generator_helper.cmake new file mode 100644 index 0000000..243593d --- /dev/null +++ b/app/src/main/cpp/Dobby/cmake/xcode_generator_helper.cmake @@ -0,0 +1,9 @@ +if(CMAKE_GENERATOR STREQUAL Xcode) + message(STATUS "[*] Detect Xcode Project") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/build/Debug) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/build/Release) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/build/Debug) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/build/Release) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/build/Debug) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/build/Release) +endif() \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/docs/compile.md b/app/src/main/cpp/Dobby/docs/compile.md new file mode 100644 index 0000000..79ded1e --- /dev/null +++ b/app/src/main/cpp/Dobby/docs/compile.md @@ -0,0 +1,90 @@ +# Build + +## CMake build options + +``` +option(DOBBY_GENERATE_SHARED "Build shared library" ON) + +option(DOBBY_DEBUG "Enable debug logging" OFF) + +option(NearBranch "Enable near branch trampoline" ON) + +option(FullFloatingPointRegisterPack "Save and pack all floating-point registers" OFF) + +option(Plugin.SymbolResolver "Enable symbol resolver" ON) + +option(Plugin.ImportTableReplace "Enable import table replace " OFF) + +option(Plugin.Android.BionicLinkerUtil "Enable android bionic linker util" OFF) + +option(BUILD_EXAMPLE "Build example" OFF) + +option(BUILD_TEST "Build test" OFF) +``` + +## Build with `scripts/platform_builder.py` + +#### Build for iphoneos + +```shell +python3 scripts/platform_builder.py --platform=iphoneos --arch=all +``` + +#### Build for macos + +``` +python3 scripts/platform_builder.py --platform=macos --arch=all +``` + +#### Build for linux + +``` +# prepare and download cmake/llvm +sh scripts/setup_linux_cross_compile.sh +python3 scripts/platform_builder.py --platform=linux --arch=all --cmake_dir=$HOME/opt/cmake-3.20.2 --llvm_dir=$HOME/opt/llvm-14.0.0 +``` + +#### Build for android + +``` +# prepare and download cmake/llvm/ndk +sh scripts/setup_linux_cross_compile.sh +sh scripts/setup_linux_cross_compile.sh +python3 scripts/platform_builder.py --platform=linux --arch=all --cmake_dir=$HOME/opt/cmake-3.20.2 --llvm_dir=$HOME/opt/llvm-14.0.0 --android_ndk_dir=$HOME/opt/ndk-r25b +``` + +## Build with CMake + +#### Build for host + +```shell +cd Dobby && mkdir cmake-build-host && cd cmake-build-host +cmake .. +make -j4 +``` + +## Build with Android Studio CMake + +``` +if(NOT TARGET dobby) +set(DOBBY_DIR /Users/jmpews/Workspace/Project.wrk/Dobby) +macro(SET_OPTION option value) + set(${option} ${value} CACHE INTERNAL "" FORCE) +endmacro() +SET_OPTION(DOBBY_DEBUG OFF) +SET_OPTION(DOBBY_GENERATE_SHARED OFF) +add_subdirectory(${DOBBY_DIR} dobby) +get_property(DOBBY_INCLUDE_DIRECTORIES + TARGET dobby + PROPERTY INCLUDE_DIRECTORIES) +include_directories( + . + ${DOBBY_INCLUDE_DIRECTORIES} + $ +) +endif() + +add_library(native-lib SHARED + ${DOBBY_DIR}/examples/socket_example.cc + native-lib.cpp) +``` diff --git a/app/src/main/cpp/Dobby/examples/CMakeLists.txt b/app/src/main/cpp/Dobby/examples/CMakeLists.txt new file mode 100644 index 0000000..71e8243 --- /dev/null +++ b/app/src/main/cpp/Dobby/examples/CMakeLists.txt @@ -0,0 +1,17 @@ +add_executable(socket_example + main.cc + socket_example.cc + ) + +target_link_libraries(socket_example + dobby + ) + + +add_library(socket_example_x SHARED + socket_example.cc + ) + +target_link_libraries(socket_example_x + dobby + ) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/examples/main.cc b/app/src/main/cpp/Dobby/examples/main.cc new file mode 100644 index 0000000..33eeddf --- /dev/null +++ b/app/src/main/cpp/Dobby/examples/main.cc @@ -0,0 +1,14 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char const *argv[]) { + + std::cout << "Start..." << std::endl; + + sleep(100); + return 0; +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/examples/socket_example.cc b/app/src/main/cpp/Dobby/examples/socket_example.cc new file mode 100644 index 0000000..4be7468 --- /dev/null +++ b/app/src/main/cpp/Dobby/examples/socket_example.cc @@ -0,0 +1,212 @@ +#include "dobby.h" + +#include "logging/logging.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +std::map *func_map; + +// clang-format off +const char *func_array[] = { +// "__loader_dlopen", + + "dlsym", + "dlclose", + + "open", + "write", + "read", + "close", + + "socket", + "connect", + "bind", + "listen", + "accept", + "send", + "recv", + + // "pthread_create" +}; + +const char *func_short_array[] = { + "accept", +}; +// clang-format on + +#define pac_strip(symbol) +#if defined(__APPLE__) && __arm64e__ +#if __has_feature(ptrauth_calls) +#define pac_strip(symbol) +//#define pac_strip(symbol) *(void **)&symbol = (void *)ptrauth_sign_unauthenticated((void *)symbol, ptrauth_key_asia, 0) +#endif +#endif + +#define install_hook(name, fn_ret_t, fn_args_t...) \ + fn_ret_t (*orig_##name)(fn_args_t); \ + fn_ret_t fake_##name(fn_args_t); \ + /* __attribute__((constructor)) */ static void install_hook_##name() { \ + void *sym_addr = DobbySymbolResolver(NULL, #name); \ + DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \ + pac_strip(orig_##name); \ + printf("install hook %s:%p:%p\n", #name, sym_addr, orig_##name); \ + } \ + fn_ret_t fake_##name(fn_args_t) + +install_hook(pthread_create, int, pthread_t *thread, const pthread_attr_t *attrs, void *(*start_routine)(void *), + void *arg, unsigned int create_flags) { + LOG(1, "pthread_create: %p", start_routine); + return orig_pthread_create(thread, attrs, start_routine, arg, create_flags); +} + +void common_handler(void *address, DobbyRegisterContext *ctx) { + auto iter = func_map->find(address); + if (iter != func_map->end()) { + LOG(1, "func %s:%p invoke", iter->second, iter->first); + } +} + +uint64_t socket_demo_server(void *ctx); + +uint64_t socket_demo_client(void *ctx); + +#if 1 + +__attribute__((constructor)) static void ctor() { + void *func = NULL; + log_set_level(0); + + func_map = new std::map(); + for (int i = 0; i < sizeof(func_array) / sizeof(char *); ++i) { + func = DobbySymbolResolver(NULL, func_array[i]); + if (func == NULL) { + LOG(1, "func %s not resolve", func_array[i]); + continue; + } + func_map->insert(std::pair(func, func_array[i])); + } + + for (auto iter = func_map->begin(), e = func_map->end(); iter != e; iter++) { + bool is_short = false; + for (int i = 0; i < sizeof(func_short_array) / sizeof(char *); ++i) { + if (strcmp(func_short_array[i], iter->second) == 0) { + is_short = true; + break; + } + } + if (is_short) { + dobby_enable_near_branch_trampoline(); + DobbyInstrument(iter->first, common_handler); + dobby_disable_near_branch_trampoline(); + } else { + DobbyInstrument(iter->first, common_handler); + } + } + +#if defined(__APPLE__) + // DobbyImportTableReplace(NULL, "_pthread_create", (void *)fake_pthread_create, (void **)&orig_pthread_create); +#endif + + install_hook_pthread_create(); + + pthread_t socket_server; + pthread_create(&socket_server, NULL, (void *(*)(void *))socket_demo_server, NULL); + + usleep(10000); + pthread_t socket_client; + pthread_create(&socket_client, NULL, (void *(*)(void *))socket_demo_client, NULL); + + // pthread_join(socket_client, 0); + // pthread_join(socket_server, 0); +} + +#include +#include +#include + +#define PORT 49494 + +uint64_t socket_demo_server(void *ctx) { + int server_fd, new_socket; + struct sockaddr_in address; + int opt = 1; + int addrlen = sizeof(address); + char buffer[1024] = {0}; + char *hello = "Hello from server"; + + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + ERROR_LOG("socket failed: %s", strerror(errno)); + return -1; + } + + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + ERROR_LOG("setsockopt: %s", strerror(errno)); + return -1; + } + + address.sin_family = AF_INET; + address.sin_port = htons(PORT); + address.sin_addr.s_addr = INADDR_ANY; + + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + ERROR_LOG("bind failed: %s", strerror(errno)); + return -1; + } + if (listen(server_fd, 3) < 0) { + ERROR_LOG("listen failed: %s", strerror(errno)); + return -1; + } + if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { + ERROR_LOG("accept failed: %s", strerror(errno)); + return -1; + } + + int ret = recv(new_socket, buffer, 1024, 0); + LOG(1, "[server] %s", buffer); + + send(new_socket, hello, strlen(hello), 0); + LOG(1, "[server] Hello message sent"); + return 0; +} + +uint64_t socket_demo_client(void *ctx) { + int sock = 0; + struct sockaddr_in serv_addr; + char *hello = "Hello from client"; + char buffer[1024] = {0}; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + ERROR_LOG("socket failed"); + return -1; + } + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + // Convert IPv4 and IPv6 addresses from text to binary form + if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { + ERROR_LOG("inet_pton failed"); + return -1; + } + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + ERROR_LOG("connect failed"); + return -1; + } + + send(sock, hello, strlen(hello), 0); + LOG(1, "[client] Hello message sent"); + + int ret = recv(sock, buffer, 1024, 0); + LOG(1, "[client] %s", buffer); + return 0; +} + +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/allocator.h b/app/src/main/cpp/Dobby/external/TINYSTL/allocator.h new file mode 100644 index 0000000..685d98c --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/allocator.h @@ -0,0 +1,49 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_ALLOCATOR_H +#define TINYSTL_ALLOCATOR_H + +#include + +namespace tinystl { + + struct allocator { + static void* static_allocate(size_t bytes) { + return operator new(bytes); + } + + static void static_deallocate(void* ptr, size_t /*bytes*/) { + operator delete(ptr); + } + }; +} + +#ifndef TINYSTL_ALLOCATOR +# define TINYSTL_ALLOCATOR ::tinystl::allocator +#endif + +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/buffer.h b/app/src/main/cpp/Dobby/external/TINYSTL/buffer.h new file mode 100644 index 0000000..7ec5d19 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/buffer.h @@ -0,0 +1,310 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_BUFFER_H +#define TINYSTL_BUFFER_H + +#include +#include +#include + +namespace tinystl { + + template + struct buffer { + T* first; + T* last; + T* capacity; + }; + + template + static inline void buffer_destroy_range_traits(T* first, T* last, pod_traits) { + for (; first < last; ++first) + first->~T(); + } + + template + static inline void buffer_destroy_range_traits(T*, T*, pod_traits) { + } + + template + static inline void buffer_destroy_range(T* first, T* last) { + buffer_destroy_range_traits(first, last, pod_traits()); + } + + template + static inline void buffer_fill_urange_traits(T* first, T* last, pod_traits) { + for (; first < last; ++first) + new(placeholder(), first) T(); + } + + template + static inline void buffer_fill_urange_traits(T* first, T* last, pod_traits) { + for (; first < last; ++first) + *first = T(); + } + + template + static inline void buffer_fill_urange_traits(T* first, T* last, const T& value, pod_traits) { + for (; first < last; ++first) + new(placeholder(), first) T(value); + } + + template + static inline void buffer_fill_urange_traits(T* first, T* last, const T& value, pod_traits) { + for (; first < last; ++first) + *first = value; + } + + template + static inline void buffer_move_urange_traits(T* dest, T* first, T* last, pod_traits) { + for (T* it = first; it != last; ++it, ++dest) + move_construct(dest, *it); + buffer_destroy_range(first, last); + } + + template + static inline void buffer_move_urange_traits(T* dest, T* first, T* last, pod_traits) { + for (; first != last; ++first, ++dest) + *dest = *first; + } + + template + static inline void buffer_bmove_urange_traits(T* dest, T* first, T* last, pod_traits) { + dest += (last - first); + for (T* it = last; it != first; --it, --dest) { + move_construct(dest - 1, *(it - 1)); + buffer_destroy_range(it - 1, it); + } + } + + template + static inline void buffer_bmove_urange_traits(T* dest, T* first, T* last, pod_traits) { + dest += (last - first); + for (T* it = last; it != first; --it, --dest) + *(dest - 1) = *(it - 1); + } + + template + static inline void buffer_move_urange(T* dest, T* first, T* last) { + buffer_move_urange_traits(dest, first, last, pod_traits()); + } + + template + static inline void buffer_bmove_urange(T* dest, T* first, T* last) { + buffer_bmove_urange_traits(dest, first, last, pod_traits()); + } + + template + static inline void buffer_fill_urange(T* first, T* last) { + buffer_fill_urange_traits(first, last, pod_traits()); + } + + template + static inline void buffer_fill_urange(T* first, T* last, const T& value) { + buffer_fill_urange_traits(first, last, value, pod_traits()); + } + + template + static inline void buffer_init(buffer* b) { + b->first = b->last = b->capacity = 0; + } + + template + static inline void buffer_destroy(buffer* b) { + buffer_destroy_range(b->first, b->last); + Alloc::static_deallocate(b->first, (size_t)((char*)b->capacity - (char*)b->first)); + } + + template + static inline void buffer_reserve(buffer* b, size_t capacity) { + if (b->first + capacity <= b->capacity) + return; + + typedef T* pointer; + const size_t size = (size_t)(b->last - b->first); + pointer newfirst = (pointer)Alloc::static_allocate(sizeof(T) * capacity); + buffer_move_urange(newfirst, b->first, b->last); + Alloc::static_deallocate(b->first, sizeof(T) * capacity); + + b->first = newfirst; + b->last = newfirst + size; + b->capacity = newfirst + capacity; + } + + template + static inline void buffer_resize(buffer* b, size_t size) { + buffer_reserve(b, size); + + buffer_fill_urange(b->last, b->first + size); + buffer_destroy_range(b->first + size, b->last); + b->last = b->first + size; + } + + template + static inline void buffer_resize(buffer* b, size_t size, const T& value) { + buffer_reserve(b, size); + + buffer_fill_urange(b->last, b->first + size, value); + buffer_destroy_range(b->first + size, b->last); + b->last = b->first + size; + } + + template + static inline void buffer_shrink_to_fit(buffer* b) { + if (b->capacity != b->last) { + if (b->last == b->first) { + const size_t capacity = (size_t)(b->capacity - b->first); + Alloc::static_deallocate(b->first, sizeof(T)*capacity); + b->capacity = b->first = b->last = nullptr; + } else { + const size_t capacity = (size_t)(b->capacity - b->first); + const size_t size = (size_t)(b->last - b->first); + T* newfirst = (T*)Alloc::static_allocate(sizeof(T) * size); + buffer_move_urange(newfirst, b->first, b->last); + Alloc::static_deallocate(b->first, sizeof(T) * capacity); + b->first = newfirst; + b->last = newfirst + size; + b->capacity = b->last; + } + } + } + + template + static inline void buffer_clear(buffer* b) { + buffer_destroy_range(b->first, b->last); + b->last = b->first; + } + + template + static inline T* buffer_insert_common(buffer* b, T* where, size_t count) { + const size_t offset = (size_t)(where - b->first); + const size_t newsize = (size_t)((b->last - b->first) + count); + if (b->first + newsize > b->capacity) + buffer_reserve(b, (newsize * 3) / 2); + + where = b->first + offset; + + if (where != b->last) + buffer_bmove_urange(where + count, where, b->last); + + b->last = b->first + newsize; + + return where; + } + + template + static inline void buffer_insert(buffer* b, T* where, const Param* first, const Param* last) { + typedef const char* pointer; + const size_t count = last - first; + const bool frombuf = ((pointer)b->first <= (pointer)first && (pointer)b->last >= (pointer)last); + size_t offset; + if (frombuf) { + offset = (pointer)first - (pointer)b->first; + if ((pointer)where <= (pointer)first) + offset += count * sizeof(T); + where = buffer_insert_common(b, where, count); + first = (Param*)((pointer)b->first + offset); + last = first + count; + } + else { + where = buffer_insert_common(b, where, count); + } + for (; first != last; ++first, ++where) + new(placeholder(), where) T(*first); + } + + template + static inline void buffer_insert(buffer* b, T* where, size_t count) { + where = buffer_insert_common(b, where, count); + for (T* end = where+count; where != end; ++where) + new(placeholder(), where) T(); + } + + template + static inline void buffer_append(buffer* b, const Param* param) { + if (b->capacity != b->last) { + new(placeholder(), b->last) T(*param); + ++b->last; + } else { + buffer_insert(b, b->last, param, param + 1); + } + } + + template + static inline void buffer_append(buffer* b) { + if (b->capacity != b->last) { + new(placeholder(), b->last) T(); + ++b->last; + } else { + buffer_insert(b, b->last, 1); + } + } + + template + static inline T* buffer_erase(buffer* b, T* first, T* last) { + typedef T* pointer; + const size_t count = (last - first); + for (pointer it = last, end = b->last, dest = first; it != end; ++it, ++dest) + move(*dest, *it); + + buffer_destroy_range(b->last - count, b->last); + + b->last -= count; + return first; + } + + template + static inline T* buffer_erase_unordered(buffer* b, T* first, T* last) { + typedef T* pointer; + const size_t count = (last - first); + const size_t tail = (b->last - last); + pointer it = b->last - ((count < tail) ? count : tail); + for (pointer end = b->last, dest = first; it != end; ++it, ++dest) + move(*dest, *it); + + buffer_destroy_range(b->last - count, b->last); + + b->last -= count; + return first; + } + + template + static inline void buffer_swap(buffer* b, buffer* other) { + typedef T* pointer; + const pointer tfirst = b->first, tlast = b->last, tcapacity = b->capacity; + b->first = other->first, b->last = other->last, b->capacity = other->capacity; + other->first = tfirst, other->last = tlast, other->capacity = tcapacity; + } + + template + static inline void buffer_move(buffer* dst, buffer* src) { + dst->first = src->first, dst->last = src->last, dst->capacity = src->capacity; + src->first = src->last = src->capacity = nullptr; + } +} + +#endif //TINYSTL_BUFFER_H diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/hash.h b/app/src/main/cpp/Dobby/external/TINYSTL/hash.h new file mode 100644 index 0000000..c03b326 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/hash.h @@ -0,0 +1,53 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_STRINGHASH_H +#define TINYSTL_STRINGHASH_H + +#include + +namespace tinystl { + + static inline size_t hash_string(const char* str, size_t len) { + // Implementation of sdbm a public domain string hash from Ozan Yigit + // see: http://www.eecs.harvard.edu/margo/papers/usenix91/paper.ps + + size_t hash = 0; + typedef const char* pointer; + for (pointer it = str, end = str + len; it != end; ++it) + hash = *it + (hash << 6) + (hash << 16) - hash; + + return hash; + } + + template + inline size_t hash(const T& value) { + const size_t asint = (size_t)value; + return hash_string((const char*)&asint, sizeof(asint)); + } +} + +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/hash_base.h b/app/src/main/cpp/Dobby/external/TINYSTL/hash_base.h new file mode 100644 index 0000000..30f449b --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/hash_base.h @@ -0,0 +1,292 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_HASH_BASE_H +#define TINYSTL_HASH_BASE_H + +#include +#include + +namespace tinystl { + + template + struct pair { + pair(); + pair(const pair& other); + pair(pair&& other); + pair(const Key& key, const Value& value); + pair(Key&& key, Value&& value); + + pair& operator=(const pair& other); + pair& operator=(pair&& other); + + Key first; + Value second; + }; + + template + inline pair::pair() { + } + + template + inline pair::pair(const pair& other) + : first(other.first) + , second(other.second) + { + } + + template + inline pair::pair(pair&& other) + : first(static_cast(other.first)) + , second(static_cast(other.second)) + { + } + + template + inline pair::pair(const Key& key, const Value& value) + : first(key) + , second(value) + { + } + + template + inline pair::pair(Key&& key, Value&& value) + : first(static_cast(key)) + , second(static_cast(value)) + { + } + + template + inline pair& pair::operator=(const pair& other) { + first = other.first; + second = other.second; + return *this; + } + + template + inline pair& pair::operator=(pair&& other) { + first = static_cast(other.first); + second = static_cast(other.second); + return *this; + } + + template + static inline pair::type, typename remove_reference::type> + make_pair(Key&& key, Value&& value) { + return pair::type, typename remove_reference::type>( + static_cast(key) + , static_cast(value) + ); + } + + + template + struct unordered_hash_node { + unordered_hash_node(const Key& key, const Value& value); + unordered_hash_node(Key&& key, Value&& value); + + const Key first; + Value second; + unordered_hash_node* next; + unordered_hash_node* prev; + + private: + unordered_hash_node& operator=(const unordered_hash_node&); + }; + + template + inline unordered_hash_node::unordered_hash_node(const Key& key, const Value& value) + : first(key) + , second(value) + { + } + + template + inline unordered_hash_node::unordered_hash_node(Key&& key, Value&& value) + : first(static_cast(key)) + , second(static_cast(value)) + { + } + + template + struct unordered_hash_node { + explicit unordered_hash_node(const Key& key); + explicit unordered_hash_node(Key&& key); + + const Key first; + unordered_hash_node* next; + unordered_hash_node* prev; + + private: + unordered_hash_node& operator=(const unordered_hash_node&); + }; + + template + inline unordered_hash_node::unordered_hash_node(const Key& key) + : first(key) + { + } + + template + inline unordered_hash_node::unordered_hash_node(Key&& key) + : first(static_cast(key)) + { + } + + template + static inline void unordered_hash_node_insert(unordered_hash_node* node, size_t hash, unordered_hash_node** buckets, size_t nbuckets) { + size_t bucket = hash & (nbuckets - 1); + + unordered_hash_node* it = buckets[bucket + 1]; + node->next = it; + if (it) { + node->prev = it->prev; + it->prev = node; + if (node->prev) + node->prev->next = node; + } else { + size_t newbucket = bucket; + while (newbucket && !buckets[newbucket]) + --newbucket; + + unordered_hash_node* prev = buckets[newbucket]; + while (prev && prev->next) + prev = prev->next; + + node->prev = prev; + if (prev) + prev->next = node; + } + + // propagate node through buckets + for (; it == buckets[bucket]; --bucket) { + buckets[bucket] = node; + if (!bucket) + break; + } + } + + template + static inline void unordered_hash_node_erase(const unordered_hash_node* where, size_t hash, unordered_hash_node** buckets, size_t nbuckets) { + size_t bucket = hash & (nbuckets - 1); + + unordered_hash_node* next = where->next; + for (; buckets[bucket] == where; --bucket) { + buckets[bucket] = next; + if (!bucket) + break; + } + + if (where->prev) + where->prev->next = where->next; + if (next) + next->prev = where->prev; + } + + template + struct unordered_hash_iterator { + Node* operator->() const; + Node& operator*() const; + Node* node; + }; + + template + struct unordered_hash_iterator { + + unordered_hash_iterator() {} + unordered_hash_iterator(unordered_hash_iterator other) + : node(other.node) + { + } + + const Node* operator->() const; + const Node& operator*() const; + const Node* node; + }; + + template + struct unordered_hash_iterator > { + const Key* operator->() const; + const Key& operator*() const; + unordered_hash_node* node; + }; + + template + static inline bool operator==(const unordered_hash_iterator& lhs, const unordered_hash_iterator& rhs) { + return lhs.node == rhs.node; + } + + template + static inline bool operator!=(const unordered_hash_iterator& lhs, const unordered_hash_iterator& rhs) { + return lhs.node != rhs.node; + } + + template + static inline void operator++(unordered_hash_iterator& lhs) { + lhs.node = lhs.node->next; + } + + template + inline Node* unordered_hash_iterator::operator->() const { + return node; + } + + template + inline Node& unordered_hash_iterator::operator*() const { + return *node; + } + + template + inline const Node* unordered_hash_iterator::operator->() const { + return node; + } + + template + inline const Node& unordered_hash_iterator::operator*() const { + return *node; + } + + template + inline const Key* unordered_hash_iterator >::operator->() const { + return &node->first; + } + + template + inline const Key& unordered_hash_iterator >::operator*() const { + return node->first; + } + + template + static inline Node unordered_hash_find(const Key& key, Node* buckets, size_t nbuckets) { + const size_t bucket = hash(key) & (nbuckets - 2); + for (Node it = buckets[bucket], end = buckets[bucket+1]; it != end; it = it->next) + if (it->first == key) + return it; + + return 0; + } +} +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/new.h b/app/src/main/cpp/Dobby/external/TINYSTL/new.h new file mode 100644 index 0000000..5f8a6f7 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/new.h @@ -0,0 +1,43 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_NEW_H +#define TINYSTL_NEW_H + +#include + +namespace tinystl { + + struct placeholder {}; +} + +inline void* operator new(size_t, tinystl::placeholder, void* ptr) { + return ptr; +} + +inline void operator delete(void*, tinystl::placeholder, void*) throw() {} + +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/stddef.h b/app/src/main/cpp/Dobby/external/TINYSTL/stddef.h new file mode 100644 index 0000000..a31dd34 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/stddef.h @@ -0,0 +1,43 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_STDDEF_H +#define TINYSTL_STDDEF_H + +#if defined(_WIN64) + typedef long long unsigned int size_t; + typedef long long int ptrdiff_t; +#elif defined(_WIN32) + typedef unsigned int size_t; + typedef int ptrdiff_t; +#elif defined (__linux__) && defined(__SIZE_TYPE__) && defined(__PTRDIFF_TYPE__) + typedef __SIZE_TYPE__ size_t; + typedef __PTRDIFF_TYPE__ ptrdiff_t; +#else +# include +#endif + +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/string.h b/app/src/main/cpp/Dobby/external/TINYSTL/string.h new file mode 100644 index 0000000..3fe45d1 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/string.h @@ -0,0 +1,295 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_STRING_H +#define TINYSTL_STRING_H + +#include +#include +#include + +namespace tinystl { + + template + class basic_string { + public: + basic_string(); + basic_string(const basic_string& other); + basic_string(basic_string&& other); + basic_string(const char* sz); + basic_string(const char* sz, size_t len); + ~basic_string(); + + basic_string& operator=(const basic_string& other); + basic_string& operator=(basic_string&& other); + + const char* c_str() const; + size_t size() const; + + void reserve(size_t size); + void resize(size_t size); + + void clear(); + void append(const char* first, const char* last); + void assign(const char* s, size_t n); + + void shrink_to_fit(); + void swap(basic_string& other); + + private: + typedef char* pointer; + pointer m_first; + pointer m_last; + pointer m_capacity; + + static const size_t c_nbuffer = 12; + char m_buffer[12]; + }; + + template + inline basic_string::basic_string() + : m_first(m_buffer) + , m_last(m_buffer) + , m_capacity(m_buffer + c_nbuffer) + { + resize(0); + } + + template + inline basic_string::basic_string(const basic_string& other) + : m_first(m_buffer) + , m_last(m_buffer) + , m_capacity(m_buffer + c_nbuffer) + { + reserve(other.size()); + append(other.m_first, other.m_last); + } + + template + inline basic_string::basic_string(basic_string&& other) + { + if (other.m_first == other.m_buffer) { + m_first = m_buffer; + m_last = m_buffer; + m_capacity = m_buffer + c_nbuffer; + reserve(other.size()); + append(other.m_first, other.m_last); + } else { + m_first = other.m_first; + m_last = other.m_last; + m_capacity = other.m_capacity; + } + other.m_first = other.m_last = other.m_buffer; + other.m_capacity = other.m_buffer + c_nbuffer; + other.resize(0); + } + + template + inline basic_string::basic_string(const char* sz) + : m_first(m_buffer) + , m_last(m_buffer) + , m_capacity(m_buffer + c_nbuffer) + { + size_t len = 0; + for (const char* it = sz; *it; ++it) + ++len; + + reserve(len); + append(sz, sz + len); + } + + template + inline basic_string::basic_string(const char* sz, size_t len) + : m_first(m_buffer) + , m_last(m_buffer) + , m_capacity(m_buffer + c_nbuffer) + { + reserve(len); + append(sz, sz + len); + } + + template + inline basic_string::~basic_string() { + if (m_first != m_buffer) + allocator::static_deallocate(m_first, m_capacity - m_first); + } + + template + inline basic_string& basic_string::operator=(const basic_string& other) { + basic_string(other).swap(*this); + return *this; + } + + template + inline basic_string& basic_string::operator=(basic_string&& other) { + basic_string(static_cast(other)).swap(*this); + return *this; + } + + template + inline const char* basic_string::c_str() const { + return m_first; + } + + template + inline size_t basic_string::size() const + { + return (size_t)(m_last - m_first); + } + + template + inline void basic_string::reserve(size_t capacity) { + if (m_first + capacity + 1 <= m_capacity) + return; + + const size_t size = (size_t)(m_last - m_first); + + pointer newfirst = (pointer)allocator::static_allocate(capacity + 1); + for (pointer it = m_first, newit = newfirst, end = m_last; it != end; ++it, ++newit) + *newit = *it; + if (m_first != m_buffer) + allocator::static_deallocate(m_first, m_capacity - m_first); + + m_first = newfirst; + m_last = newfirst + size; + m_capacity = m_first + capacity; + } + + template + inline void basic_string::resize(size_t size) { + const size_t prevSize = m_last-m_first; + reserve(size); + if (size > prevSize) + for (pointer it = m_last, end = m_first + size + 1; it < end; ++it) + *it = 0; + else if (m_last != m_first) + m_first[size] = 0; + + m_last = m_first + size; + } + + template + inline void basic_string::clear() { + resize(0); + } + + template + inline void basic_string::append(const char* first, const char* last) { + const size_t newsize = (size_t)((m_last - m_first) + (last - first) + 1); + if (m_first + newsize > m_capacity) + reserve((newsize * 3) / 2); + + for (; first != last; ++m_last, ++first) + *m_last = *first; + *m_last = 0; + } + + template + inline void basic_string::assign(const char* sz, size_t n) { + clear(); + append(sz, sz+n); + } + + template + inline void basic_string::shrink_to_fit() { + if (m_first == m_buffer) { + } else if (m_last == m_first) { + const size_t capacity = (size_t)(m_capacity - m_first); + if (capacity) + allocator::static_deallocate(m_first, capacity+1); + m_capacity = m_first; + } else if (m_capacity != m_last) { + const size_t size = (size_t)(m_last - m_first); + char* newfirst = (pointer)allocator::static_allocate(size+1); + for (pointer in = m_first, out = newfirst; in != m_last + 1; ++in, ++out) + *out = *in; + if (m_first != m_capacity) + allocator::static_deallocate(m_first, m_capacity+1-m_first); + m_first = newfirst; + m_last = newfirst+size; + m_capacity = m_last; + } + } + + template + inline void basic_string::swap(basic_string& other) { + const pointer tfirst = m_first, tlast = m_last, tcapacity = m_capacity; + m_first = other.m_first, m_last = other.m_last, m_capacity = other.m_capacity; + other.m_first = tfirst, other.m_last = tlast, other.m_capacity = tcapacity; + + char tbuffer[c_nbuffer]; + + if (m_first == other.m_buffer) + for (pointer it = other.m_buffer, end = m_last, out = tbuffer; it != end; ++it, ++out) + *out = *it; + + if (other.m_first == m_buffer) { + other.m_last = other.m_last - other.m_first + other.m_buffer; + other.m_first = other.m_buffer; + other.m_capacity = other.m_buffer + c_nbuffer; + + for (pointer it = other.m_first, end = other.m_last, in = m_buffer; it != end; ++it, ++in) + *it = *in; + *other.m_last = 0; + } + + if (m_first == other.m_buffer) { + m_last = m_last - m_first + m_buffer; + m_first = m_buffer; + m_capacity = m_buffer + c_nbuffer; + + for (pointer it = m_first, end = m_last, in = tbuffer; it != end; ++it, ++in) + *it = *in; + *m_last = 0; + } + } + + template + inline bool operator==(const basic_string& lhs, const basic_string& rhs) { + typedef const char* pointer; + + const size_t lsize = lhs.size(), rsize = rhs.size(); + if (lsize != rsize) + return false; + + pointer lit = lhs.c_str(), rit = rhs.c_str(); + pointer lend = lit + lsize; + while (lit != lend) + if (*lit++ != *rit++) + return false; + + return true; + } + + template + static inline size_t hash(const basic_string& value) { + return hash_string(value.c_str(), value.size()); + } + + typedef basic_string string; +} + +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/string_view.h b/app/src/main/cpp/Dobby/external/TINYSTL/string_view.h new file mode 100644 index 0000000..beae9c4 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/string_view.h @@ -0,0 +1,147 @@ +/*- + * Copyright 2012-1017 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_STRING_VIEW_H +#define TINYSTL_STRING_VIEW_H + +#include + +namespace tinystl { + + class string_view + { + public: + typedef char value_type; + typedef char* pointer; + typedef const char* const_pointer; + typedef char& reference; + typedef const char& const_reference; + typedef const_pointer iterator; + typedef const_pointer const_iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + static constexpr size_type npos = size_type(-1); + + constexpr string_view(); + constexpr string_view(const char* s, size_type count); + constexpr string_view(const char* s); + constexpr string_view(const string_view&) = default; + string_view& operator=(const string_view&) = default; + + constexpr const char* data() const; + constexpr char operator[](size_type pos) const; + constexpr size_type size() const; + constexpr bool empty() const; + constexpr iterator begin() const; + constexpr const_iterator cbegin() const; + constexpr iterator end() const; + constexpr const_iterator cend() const; + constexpr string_view substr(size_type pos = 0, size_type count = npos) const; + constexpr void swap(string_view& v); + + private: + string_view(decltype(nullptr)) = delete; + + static constexpr size_type strlen(const char*); + + const char* m_str; + size_type m_size; + }; + + constexpr string_view::string_view() + : m_str(nullptr) + , m_size(0) + { + } + + constexpr string_view::string_view(const char* s, size_type count) + : m_str(s) + , m_size(count) + { + } + + constexpr string_view::string_view(const char* s) + : m_str(s) + , m_size(strlen(s)) + { + } + + constexpr const char* string_view::data() const { + return m_str; + } + + constexpr char string_view::operator[](size_type pos) const { + return m_str[pos]; + } + + constexpr string_view::size_type string_view::size() const { + return m_size; + } + + constexpr bool string_view::empty() const { + return 0 == m_size; + } + + constexpr string_view::iterator string_view::begin() const { + return m_str; + } + + constexpr string_view::const_iterator string_view::cbegin() const { + return m_str; + } + + constexpr string_view::iterator string_view::end() const { + return m_str + m_size; + } + + constexpr string_view::const_iterator string_view::cend() const { + return m_str + m_size; + } + + constexpr string_view string_view::substr(size_type pos, size_type count) const { + return string_view(m_str + pos, npos == count ? m_size - pos : count); + } + + constexpr void string_view::swap(string_view& v) { + const char* strtmp = m_str; + size_type sizetmp = m_size; + m_str = v.m_str; + m_size = v.m_size; + v.m_str = strtmp; + v.m_size = sizetmp; + } + + constexpr string_view::size_type string_view::strlen(const char* s) { + for (size_t len = 0; ; ++len) { + if (0 == s[len]) { + return len; + } + } + } +} + +#endif // TINYSTL_STRING_VIEW_H diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/traits.h b/app/src/main/cpp/Dobby/external/TINYSTL/traits.h new file mode 100644 index 0000000..84574ee --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/traits.h @@ -0,0 +1,100 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_TRAITS_H +#define TINYSTL_TRAITS_H + +#include + +#if defined(__GNUC__) +# define TINYSTL_TRY_POD_OPTIMIZATION(t) __is_pod(t) +#elif defined(_MSC_VER) +# define TINYSTL_TRY_POD_OPTIMIZATION(t) (!__is_class(t) || __is_pod(t)) +#else +# define TINYSTL_TRY_POD_OPTIMIZATION(t) false +#endif + +namespace tinystl { + template struct pod_traits {}; + + template struct swap_holder; + + template + static inline void move_impl(T& a, T& b, ...) { + a = b; + } + + template + static inline void move_impl(T& a, T& b, T*, swap_holder* = 0) { + a.swap(b); + } + + template + static inline void move(T& a, T&b) { + move_impl(a, b, (T*)0); + } + + template + static inline void move_construct_impl(T* a, T& b, ...) { + new(placeholder(), a) T(b); + } + + template + static inline void move_construct_impl(T* a, T& b, void*, swap_holder* = 0) { + // If your type T does not have a default constructor, simply insert: + // struct tinystl_nomove_construct; + // in the class definition + new(placeholder(), a) T; + a->swap(b); + } + + template + static inline void move_construct_impl(T* a, T& b, T*, typename T::tinystl_nomove_construct* = 0) { + new(placeholder(), a) T(b); + } + + template + static inline void move_construct(T* a, T& b) { + move_construct_impl(a, b, (T*)0); + } + + template + struct remove_reference { + typedef T type; + }; + + template + struct remove_reference { + typedef T type; + }; + + template + struct remove_reference { + typedef T type; + }; +} + +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/unordered_map.h b/app/src/main/cpp/Dobby/external/TINYSTL/unordered_map.h new file mode 100644 index 0000000..4be6a78 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/unordered_map.h @@ -0,0 +1,289 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_UNORDERED_MAP_H +#define TINYSTL_UNORDERED_MAP_H + +#include +#include +#include +#include + +namespace tinystl { + + template + class unordered_map { + public: + unordered_map(); + unordered_map(const unordered_map& other); + unordered_map(unordered_map&& other); + ~unordered_map(); + + unordered_map& operator=(const unordered_map& other); + unordered_map& operator=(unordered_map&& other); + + typedef pair value_type; + + typedef unordered_hash_iterator > const_iterator; + typedef unordered_hash_iterator > iterator; + + iterator begin(); + iterator end(); + + const_iterator begin() const; + const_iterator end() const; + + void clear(); + bool empty() const; + size_t size() const; + + const_iterator find(const Key& key) const; + iterator find(const Key& key); + pair insert(const pair& p); + pair emplace(pair&& p); + void erase(const_iterator where); + + Value& operator[](const Key& key); + + void swap(unordered_map& other); + + private: + + void rehash(size_t nbuckets); + + typedef unordered_hash_node* pointer; + + size_t m_size; + tinystl::buffer m_buckets; + }; + + template + inline unordered_map::unordered_map() + : m_size(0) + { + buffer_init(&m_buckets); + buffer_resize(&m_buckets, 9, 0); + } + + template + inline unordered_map::unordered_map(const unordered_map& other) + : m_size(other.m_size) + { + const size_t nbuckets = (size_t)(other.m_buckets.last - other.m_buckets.first); + buffer_init(&m_buckets); + buffer_resize(&m_buckets, nbuckets, 0); + + for (pointer it = *other.m_buckets.first; it; it = it->next) { + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(it->first, it->second); + newnode->next = newnode->prev = 0; + + unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1); + } + } + + template + inline unordered_map::unordered_map(unordered_map&& other) + : m_size(other.m_size) + { + buffer_move(&m_buckets, &other.m_buckets); + other.m_size = 0; + } + + template + inline unordered_map::~unordered_map() { + if (m_buckets.first != m_buckets.last) + clear(); + buffer_destroy(&m_buckets); + } + + template + inline unordered_map& unordered_map::operator=(const unordered_map& other) { + unordered_map(other).swap(*this); + return *this; + } + + template + inline unordered_map& unordered_map::operator=(unordered_map&& other) { + unordered_map(static_cast(other)).swap(*this); + return *this; + } + + template + inline typename unordered_map::iterator unordered_map::begin() { + iterator it; + it.node = *m_buckets.first; + return it; + } + + template + inline typename unordered_map::iterator unordered_map::end() { + iterator it; + it.node = 0; + return it; + } + + template + inline typename unordered_map::const_iterator unordered_map::begin() const { + const_iterator cit; + cit.node = *m_buckets.first; + return cit; + } + + template + inline typename unordered_map::const_iterator unordered_map::end() const { + const_iterator cit; + cit.node = 0; + return cit; + } + + template + inline bool unordered_map::empty() const { + return m_size == 0; + } + + template + inline size_t unordered_map::size() const { + return m_size; + } + + template + inline void unordered_map::clear() { + pointer it = *m_buckets.first; + while (it) { + const pointer next = it->next; + it->~unordered_hash_node(); + Alloc::static_deallocate(it, sizeof(unordered_hash_node)); + + it = next; + } + + m_buckets.last = m_buckets.first; + buffer_resize(&m_buckets, 9, 0); + m_size = 0; + } + + template + inline typename unordered_map::iterator unordered_map::find(const Key& key) { + iterator result; + result.node = unordered_hash_find(key, m_buckets.first, (size_t)(m_buckets.last - m_buckets.first)); + return result; + } + + template + inline typename unordered_map::const_iterator unordered_map::find(const Key& key) const { + iterator result; + result.node = unordered_hash_find(key, m_buckets.first, (size_t)(m_buckets.last - m_buckets.first)); + return result; + } + + template + inline void unordered_map::rehash(size_t nbuckets) { + if (m_size + 1 > 4 * nbuckets) { + pointer root = *m_buckets.first; + + const size_t newnbuckets = ((size_t)(m_buckets.last - m_buckets.first) - 1) * 8; + m_buckets.last = m_buckets.first; + buffer_resize(&m_buckets, newnbuckets + 1, 0); + unordered_hash_node** buckets = m_buckets.first; + + while (root) { + const pointer next = root->next; + root->next = root->prev = 0; + unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets); + root = next; + } + } + } + + template + inline pair::iterator, bool> unordered_map::insert(const pair& p) { + pair result; + result.second = false; + + result.first = find(p.first); + if (result.first.node != 0) + return result; + + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(p.first, p.second); + newnode->next = newnode->prev = 0; + + const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); + unordered_hash_node_insert(newnode, hash(p.first), m_buckets.first, nbuckets - 1); + + ++m_size; + rehash(nbuckets); + + result.first.node = newnode; + result.second = true; + return result; + } + + template + inline pair::iterator, bool> unordered_map::emplace(pair&& p) { + pair result; + result.second = false; + + result.first = find(p.first); + if (result.first.node != 0) + return result; + + const size_t keyhash = hash(p.first); + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(static_cast(p.first), static_cast(p.second)); + newnode->next = newnode->prev = 0; + + const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); + unordered_hash_node_insert(newnode, keyhash, m_buckets.first, nbuckets - 1); + + ++m_size; + rehash(nbuckets); + + result.first.node = newnode; + result.second = true; + return result; + } + + template + inline void unordered_map::erase(const_iterator where) { + unordered_hash_node_erase(where.node, hash(where->first), m_buckets.first, (size_t)(m_buckets.last - m_buckets.first) - 1); + + where->~unordered_hash_node(); + Alloc::static_deallocate((void*)where.node, sizeof(unordered_hash_node)); + --m_size; + } + + template + inline Value& unordered_map::operator[](const Key& key) { + return insert(pair(key, Value())).first->second; + } + + template + inline void unordered_map::swap(unordered_map& other) { + size_t tsize = other.m_size; + other.m_size = m_size, m_size = tsize; + buffer_swap(&m_buckets, &other.m_buckets); + } +} +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/unordered_set.h b/app/src/main/cpp/Dobby/external/TINYSTL/unordered_set.h new file mode 100644 index 0000000..450fbc5 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/unordered_set.h @@ -0,0 +1,265 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_UNORDERED_SET_H +#define TINYSTL_UNORDERED_SET_H + +#include +#include +#include +#include + +namespace tinystl { + + template + class unordered_set { + public: + unordered_set(); + unordered_set(const unordered_set& other); + unordered_set(unordered_set&& other); + ~unordered_set(); + + unordered_set& operator=(const unordered_set& other); + unordered_set& operator=(unordered_set&& other); + + typedef unordered_hash_iterator > const_iterator; + typedef const_iterator iterator; + + iterator begin() const; + iterator end() const; + + void clear(); + bool empty() const; + size_t size() const; + + iterator find(const Key& key) const; + pair insert(const Key& key); + pair emplace(Key&& key); + void erase(iterator where); + size_t erase(const Key& key); + + void swap(unordered_set& other); + + private: + + void rehash(size_t nbuckets); + + typedef unordered_hash_node* pointer; + + size_t m_size; + tinystl::buffer m_buckets; + }; + + template + inline unordered_set::unordered_set() + : m_size(0) + { + buffer_init(&m_buckets); + buffer_resize(&m_buckets, 9, 0); + } + + template + inline unordered_set::unordered_set(const unordered_set& other) + : m_size(other.m_size) + { + const size_t nbuckets = (size_t)(other.m_buckets.last - other.m_buckets.first); + buffer_init(&m_buckets); + buffer_resize(&m_buckets, nbuckets, 0); + + for (pointer it = *other.m_buckets.first; it; it = it->next) { + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(*it); + newnode->next = newnode->prev = 0; + unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1); + } + } + + template + inline unordered_set::unordered_set(unordered_set&& other) + : m_size(other.m_size) + { + buffer_move(&m_buckets, &other.m_buckets); + other.m_size = 0; + } + + template + inline unordered_set::~unordered_set() { + if (m_buckets.first != m_buckets.last) + clear(); + buffer_destroy(&m_buckets); + } + + template + inline unordered_set& unordered_set::operator=(const unordered_set& other) { + unordered_set(other).swap(*this); + return *this; + } + + template + inline unordered_set& unordered_set::operator=(unordered_set&& other) { + unordered_set(static_cast(other)).swap(*this); + return *this; + } + + template + inline typename unordered_set::iterator unordered_set::begin() const { + iterator cit; + cit.node = *m_buckets.first; + return cit; + } + + template + inline typename unordered_set::iterator unordered_set::end() const { + iterator cit; + cit.node = 0; + return cit; + } + + template + inline bool unordered_set::empty() const { + return m_size == 0; + } + + template + inline size_t unordered_set::size() const { + return m_size; + } + + template + inline void unordered_set::clear() { + pointer it = *m_buckets.first; + while (it) { + const pointer next = it->next; + it->~unordered_hash_node(); + Alloc::static_deallocate(it, sizeof(unordered_hash_node)); + + it = next; + } + + m_buckets.last = m_buckets.first; + buffer_resize(&m_buckets, 9, 0); + m_size = 0; + } + + template + inline typename unordered_set::iterator unordered_set::find(const Key& key) const { + iterator result; + result.node = unordered_hash_find(key, m_buckets.first, (size_t)(m_buckets.last - m_buckets.first)); + return result; + } + + template + inline void unordered_set::rehash(size_t nbuckets) { + if (m_size + 1 > 4 * nbuckets) { + pointer root = *m_buckets.first; + + const size_t newnbuckets = ((size_t)(m_buckets.last - m_buckets.first) - 1) * 8; + m_buckets.last = m_buckets.first; + buffer_resize(&m_buckets, newnbuckets + 1, 0); + unordered_hash_node** buckets = m_buckets.first; + + while (root) { + const pointer next = root->next; + root->next = root->prev = 0; + unordered_hash_node_insert(root, hash(root->first), buckets, newnbuckets); + root = next; + } + } + } + + template + inline pair::iterator, bool> unordered_set::insert(const Key& key) { + pair result; + result.second = false; + + result.first = find(key); + if (result.first.node != 0) + return result; + + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(key); + newnode->next = newnode->prev = 0; + + const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); + unordered_hash_node_insert(newnode, hash(key), m_buckets.first, nbuckets - 1); + + ++m_size; + rehash(nbuckets); + + result.first.node = newnode; + result.second = true; + return result; + } + + template + inline pair::iterator, bool> unordered_set::emplace(Key&& key) { + pair result; + result.second = false; + + result.first = find(key); + if (result.first.node != 0) + return result; + + const size_t keyhash = hash(key); + unordered_hash_node* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node))) unordered_hash_node(static_cast(key)); + newnode->next = newnode->prev = 0; + + const size_t nbuckets = (size_t)(m_buckets.last - m_buckets.first); + unordered_hash_node_insert(newnode, keyhash, m_buckets.first, nbuckets - 1); + + ++m_size; + rehash(nbuckets); + + result.first.node = newnode; + result.second = true; + return result; + } + + template + inline void unordered_set::erase(iterator where) { + unordered_hash_node_erase(where.node, hash(where.node->first), m_buckets.first, (size_t)(m_buckets.last - m_buckets.first) - 1); + + where.node->~unordered_hash_node(); + Alloc::static_deallocate((void*)where.node, sizeof(unordered_hash_node)); + --m_size; + } + + template + inline size_t unordered_set::erase(const Key& key) { + const iterator it = find(key); + if (it.node == 0) + return 0; + + erase(it); + return 1; + } + + template + void unordered_set::swap(unordered_set& other) { + size_t tsize = other.m_size; + other.m_size = m_size, m_size = tsize; + buffer_swap(&m_buckets, &other.m_buckets); + } +} +#endif diff --git a/app/src/main/cpp/Dobby/external/TINYSTL/vector.h b/app/src/main/cpp/Dobby/external/TINYSTL/vector.h new file mode 100644 index 0000000..32eae1f --- /dev/null +++ b/app/src/main/cpp/Dobby/external/TINYSTL/vector.h @@ -0,0 +1,336 @@ +/*- + * Copyright 2012-2018 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYSTL_VECTOR_H +#define TINYSTL_VECTOR_H + +#include +#include +#include +#include + +namespace tinystl { + template + class vector { + public: + vector(); + vector(const vector& other); + vector(vector&& other); + vector(size_t size); + vector(size_t size, const T& value); + vector(const T* first, const T* last); + ~vector(); + + vector& operator=(const vector& other); + vector& operator=(vector&& other); + + void assign(const T* first, const T* last); + + const T* data() const; + T* data(); + size_t size() const; + size_t capacity() const; + bool empty() const; + + T& operator[](size_t idx); + const T& operator[](size_t idx) const; + + const T& front() const; + T& front(); + const T& back() const; + T& back(); + + void resize(size_t size); + void resize(size_t size, const T& value); + void clear(); + void reserve(size_t capacity); + + void push_back(const T& t); + void pop_back(); + + void emplace_back(); + template + void emplace_back(const Param& param); + + void shrink_to_fit(); + + void swap(vector& other); + + typedef T value_type; + + typedef T* iterator; + iterator begin(); + iterator end(); + + typedef const T* const_iterator; + const_iterator begin() const; + const_iterator end() const; + + void insert(iterator where); + void insert(iterator where, const T& value); + void insert(iterator where, const T* first, const T* last); + + template + void emplace(iterator where, const Param& param); + + iterator erase(iterator where); + iterator erase(iterator first, iterator last); + + iterator erase_unordered(iterator where); + iterator erase_unordered(iterator first, iterator last); + + private: + buffer m_buffer; + }; + + template + inline vector::vector() { + buffer_init(&m_buffer); + } + + template + inline vector::vector(const vector& other) { + buffer_init(&m_buffer); + buffer_reserve(&m_buffer, other.size()); + buffer_insert(&m_buffer, m_buffer.last, other.m_buffer.first, other.m_buffer.last); + } + + template + inline vector::vector(vector&& other) { + buffer_move(&m_buffer, &other.m_buffer); + } + + template + inline vector::vector(size_t size) { + buffer_init(&m_buffer); + buffer_resize(&m_buffer, size); + } + + template + inline vector::vector(size_t size, const T& value) { + buffer_init(&m_buffer); + buffer_resize(&m_buffer, size, value); + } + + template + inline vector::vector(const T* first, const T* last) { + buffer_init(&m_buffer); + buffer_insert(&m_buffer, m_buffer.last, first, last); + } + + template + inline vector::~vector() { + buffer_destroy(&m_buffer); + } + + template + inline vector& vector::operator=(const vector& other) { + vector(other).swap(*this); + return *this; + } + + template + vector& vector::operator=(vector&& other) { + buffer_destroy(&m_buffer); + buffer_move(&m_buffer, &other.m_buffer); + return *this; + } + + template + inline void vector::assign(const T* first, const T* last) { + buffer_clear(&m_buffer); + buffer_insert(&m_buffer, m_buffer.last, first, last); + } + + template + inline const T* vector::data() const { + return m_buffer.first; + } + + template + inline T* vector::data() { + return m_buffer.first; + } + + template + inline size_t vector::size() const { + return (size_t)(m_buffer.last - m_buffer.first); + } + + template + inline size_t vector::capacity() const { + return (size_t)(m_buffer.capacity - m_buffer.first); + } + + template + inline bool vector::empty() const { + return m_buffer.last == m_buffer.first; + } + + template + inline T& vector::operator[](size_t idx) { + return m_buffer.first[idx]; + } + + template + inline const T& vector::operator[](size_t idx) const { + return m_buffer.first[idx]; + } + + template + inline const T& vector::front() const { + return m_buffer.first[0]; + } + + template + inline T& vector::front() { + return m_buffer.first[0]; + } + + template + inline const T& vector::back() const { + return m_buffer.last[-1]; + } + + template + inline T& vector::back() { + return m_buffer.last[-1]; + } + + template + inline void vector::resize(size_t size) { + buffer_resize(&m_buffer, size); + } + + template + inline void vector::resize(size_t size, const T& value) { + buffer_resize(&m_buffer, size, value); + } + + template + inline void vector::clear() { + buffer_clear(&m_buffer); + } + + template + inline void vector::reserve(size_t capacity) { + buffer_reserve(&m_buffer, capacity); + } + + template + inline void vector::push_back(const T& t) { + buffer_append(&m_buffer, &t); + } + + template + inline void vector::emplace_back() { + buffer_append(&m_buffer); + } + + template + template + inline void vector::emplace_back(const Param& param) { + buffer_append(&m_buffer, ¶m); + } + + template + inline void vector::pop_back() { + buffer_erase(&m_buffer, m_buffer.last - 1, m_buffer.last); + } + + template + inline void vector::shrink_to_fit() { + buffer_shrink_to_fit(&m_buffer); + } + + template + inline void vector::swap(vector& other) { + buffer_swap(&m_buffer, &other.m_buffer); + } + + template + inline typename vector::iterator vector::begin() { + return m_buffer.first; + } + + template + inline typename vector::iterator vector::end() { + return m_buffer.last; + } + + template + inline typename vector::const_iterator vector::begin() const { + return m_buffer.first; + } + + template + inline typename vector::const_iterator vector::end() const { + return m_buffer.last; + } + + template + inline void vector::insert(typename vector::iterator where) { + buffer_insert(&m_buffer, where, 1); + } + + template + inline void vector::insert(iterator where, const T& value) { + buffer_insert(&m_buffer, where, &value, &value + 1); + } + + template + inline void vector::insert(iterator where, const T* first, const T* last) { + buffer_insert(&m_buffer, where, first, last); + } + + template + inline typename vector::iterator vector::erase(iterator where) { + return buffer_erase(&m_buffer, where, where + 1); + } + + template + inline typename vector::iterator vector::erase(iterator first, iterator last) { + return buffer_erase(&m_buffer, first, last); + } + + template + inline typename vector::iterator vector::erase_unordered(iterator where) { + return buffer_erase_unordered(&m_buffer, where, where + 1); + } + + template + inline typename vector::iterator vector::erase_unordered(iterator first, iterator last) { + return buffer_erase_unordered(&m_buffer, first, last); + } + + template + template + void vector::emplace(typename vector::iterator where, const Param& param) { + buffer_insert(&m_buffer, where, ¶m, ¶m + 1); + } +} + +#endif // TINYSTL_VECTOR_H diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/CMakeLists.txt b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/CMakeLists.txt new file mode 100644 index 0000000..115c9fd --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/CMakeLists.txt @@ -0,0 +1,18 @@ +include_directories(.) + +if(NOT BUILDING_KERNEL) + set(SOURCE_FILE_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/variable_cache.c + ${CMAKE_CURRENT_SOURCE_DIR}/async_logger.cc + ${CMAKE_CURRENT_SOURCE_DIR}/format_printer.cc + ) +else() + set(SOURCE_FILE_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/format_printer.cc + ) +endif() + +add_library(misc_helper + ${SOURCE_FILE_LIST} + ${SOURCE_HEADER_LIST} +) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/async_logger.cc b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/async_logger.cc new file mode 100644 index 0000000..49b11cb --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/async_logger.cc @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define aync_logger_buffer_size (20 * 1024 * 1024) +int async_logger_buffer_cursor = 0; +char async_logger_buffer[aync_logger_buffer_size]; + +static pthread_mutex_t async_logger_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int output_fd = -1; + +void async_logger_print(char *str) { + pthread_mutex_lock(&async_logger_mutex); +#if 0 + { + write(STDOUT_FILENO, str, strlen(str) + 1); + } +#endif + memcpy(async_logger_buffer + async_logger_buffer_cursor, str, strlen(str)); + async_logger_buffer_cursor += strlen(str); + pthread_mutex_unlock(&async_logger_mutex); + return; +} + +static void *async_logger_print_impl(void *ctx) { + while (1) { + pthread_mutex_lock(&async_logger_mutex); + if (async_logger_buffer_cursor > 0) { + write(output_fd, async_logger_buffer, async_logger_buffer_cursor); + async_logger_buffer_cursor = 0; + } + pthread_mutex_unlock(&async_logger_mutex); + sleep(1); + } +} + +void async_logger_init(char *logger_path) { + static int async_logger_initialized = 0; + if (async_logger_initialized) + return; + async_logger_initialized = 1; + + // init stdout write lock + pthread_mutex_t write_mutex; + pthread_mutex_init(&write_mutex, NULL); + + output_fd = STDOUT_FILENO; + if (logger_path) { + int fd = open(logger_path, O_CREAT | O_WRONLY | O_TRUNC, 0644); + output_fd = fd; + } + + // init async logger + pthread_mutex_init(&async_logger_mutex, NULL); + pthread_t async_logger_thread; + int ret = pthread_create(&async_logger_thread, NULL, async_logger_print_impl, NULL); +} diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.cc b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.cc new file mode 100644 index 0000000..bc080f6 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.cc @@ -0,0 +1,129 @@ +#include "pthread_helper.h" +#include +#ifdef _WIN32 + +typedef void (*windows_thread)(void *); + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { + uintptr_t handle = _beginthread((windows_thread)start_routine, 0, arg); + thread->handle = (HANDLE)handle; + if (thread->handle == (HANDLE)-1) { + return 1; + } else { + return 0; + } +} + +int pthread_detach(pthread_t thread) { + /* Do nothing */ + return 0; +} + +void pthread_exit(void *value_ptr) { + _endthread(); +} + +int pthread_join(pthread_t thread, void **value_ptr) { + DWORD retvalue = WaitForSingleObject(thread.handle, INFINITE); + if (retvalue == WAIT_OBJECT_0) { + return 0; + } else { + return EINVAL; + } +} + +pthread_t pthread_self(void) { + pthread_t pt; + pt.handle = GetCurrentThread(); + return pt; +} + +int pthread_cancel(pthread_t thread) { + fprintf(stderr, "DO NOT USE THIS FUNCTION. pthread_cancel\n"); + abort(); + return 0; +} + +/* --------------------- MUTEX --------------------*/ + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) { + /* do nothing */ + return 0; +} + +int pthread_mutexattr_init(pthread_mutexattr_t *attr) { + /* do nothing */ + return 0; +} + +int pthread_mutex_destroy(pthread_mutex_t *mutex) { + return !CloseHandle(mutex->handle); +} + +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { + HANDLE handle = CreateMutex(NULL, FALSE, NULL); + if (handle != NULL) { + mutex->handle = handle; + return 0; + } else { + return 1; + } +} + +int pthread_mutex_lock(pthread_mutex_t *mutex) { + DWORD retvalue = WaitForSingleObject(mutex->handle, INFINITE); + if (retvalue == WAIT_OBJECT_0) { + return 0; + } else { + return EINVAL; + } +} + +int pthread_mutex_trylock(pthread_mutex_t *mutex) { + DWORD retvalue = WaitForSingleObject(mutex->handle, 0); + if (retvalue == WAIT_OBJECT_0) { + return 0; + } else if (retvalue == WAIT_TIMEOUT) { + return EBUSY; + } else { + return EINVAL; + } +} + +int pthread_mutex_unlock(pthread_mutex_t *mutex) { + return !ReleaseMutex(mutex->handle); +} + +/* ------------------- Thead Specific Data ------------------ */ + +int pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)) { + DWORD dkey = TlsAlloc(); + if (dkey != 0xFFFFFFFF) { + *key = dkey; + return 0; + } else { + return EAGAIN; + } +} + +int pthread_key_delete(pthread_key_t key) { + if (TlsFree(key)) { + return 0; + } else { + return EINVAL; + } +} + +int pthread_setspecific(pthread_key_t key, const void *pointer) { + if (TlsSetValue(key, (LPVOID)pointer)) { + return 0; + } else { + return EINVAL; + } +} + +void *pthread_getspecific(pthread_key_t key) { + return TlsGetValue(key); +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.h b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.h new file mode 100644 index 0000000..3ed01f6 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.h @@ -0,0 +1,85 @@ +/* + * light weight pthread compatible library for Windows + * (C) 2009 Okamura Yasunobu + * + * WARNING This library does NOT support all future of pthread + * + */ + +#ifndef CROSS_THREAD_H +#define CROSS_THREAD_H + +#ifdef _WIN32 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +typedef struct pthread_tag { + HANDLE handle; +} pthread_t; + +typedef struct pthread_mutex_tag { + HANDLE handle; +} pthread_mutex_t; + +/* stub */ +typedef struct pthread_attr_tag { + int attr; +} pthread_attr_t; + +typedef struct pthread_mutexattr_tag { + int attr; +} pthread_mutexattr_t; + +typedef DWORD pthread_key_t; + +/* ignore attribute */ +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); + +/* ignore value_ptr */ +void pthread_exit(void *value_ptr); + +/* ignore value_ptr */ +int pthread_join(pthread_t thread, void **value_ptr); + +pthread_t pthread_self(void); + +/* do nothing */ +int pthread_detach(pthread_t thread); + +/* DO NOT USE */ +int pthread_cancel(pthread_t thread); + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); /* do nothing */ +int pthread_mutexattr_init(pthread_mutexattr_t *attr); /* do nothing */ + +int pthread_mutex_destroy(pthread_mutex_t *mutex); +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); +int pthread_mutex_lock(pthread_mutex_t *mutex); +int pthread_mutex_trylock(pthread_mutex_t *mutex); +int pthread_mutex_unlock(pthread_mutex_t *mutex); + +/* ignore deconstructor */ +int pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)); +int pthread_key_delete(pthread_key_t key); +int pthread_setspecific(pthread_key_t key, const void *pointer); +void *pthread_getspecific(pthread_key_t key); + +#define sleep(num) Sleep(1000 * (num)) + +#ifdef __cplusplus +} +#endif + +#else +#include +#include +#define Sleep(num) usleep(num * 1000) +#endif + +#endif /* CROSS_THREAD_H */ diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/unistd_helper.h b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/unistd_helper.h new file mode 100644 index 0000000..d990fa3 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/unistd_helper.h @@ -0,0 +1,30 @@ +#ifdef _WIN32 + +#include +#define open _open +#define read _read +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_CREAT _O_CREAT +#define O_TRUNC _O_TRUNC + +#define ssize_t int + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +/* should be in some equivalent to */ +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#else + +#include + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/format_printer.cc b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/format_printer.cc new file mode 100644 index 0000000..07ca440 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/format_printer.cc @@ -0,0 +1,11 @@ +#include "misc-helper/format_printer.h" + +void hexdump(const uint8_t *bytes, size_t len) { + size_t ix; + for (ix = 0; ix < len; ++ix) { + if (ix != 0 && !(ix % 16)) + RAW_LOG(0, "\n"); + RAW_LOG(0, "%02X ", bytes[ix]); + } + RAW_LOG(0, "\n"); +} diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/async_logger.h b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/async_logger.h new file mode 100644 index 0000000..03e0d4e --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/async_logger.h @@ -0,0 +1,8 @@ +#ifndef ASYNC_LOGGER_H +#define ASYNC_LOGGER_H + +void async_logger_print(char *str); + +void async_logger_init(char *logger_path); + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/format_printer.h b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/format_printer.h new file mode 100644 index 0000000..3f9a434 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/format_printer.h @@ -0,0 +1,3 @@ +#include "common_header.h" + +void hexdump(const uint8_t *bytes, size_t len); \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/variable_cache.h b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/variable_cache.h new file mode 100644 index 0000000..bf490fd --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/variable_cache.h @@ -0,0 +1,17 @@ +#ifndef VARIABLE_CACHE_H +#define VARIABLE_CACHE_H + +#include + +#define cache_set stash +void cache_set(const char *name, uint64_t value); + +#define cache_get(x) cache(x) +#define assert_cache(x) (assert(cache(x)), cache(x)) +uint64_t cache_get(const char *name); + +int serialized_to_file(const char *filepath); + +int unserialized_from_file(const char *filepath); + +#endif diff --git a/app/src/main/cpp/Dobby/external/deprecated/misc-helper/variable_cache.c b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/variable_cache.c new file mode 100644 index 0000000..895a2cb --- /dev/null +++ b/app/src/main/cpp/Dobby/external/deprecated/misc-helper/variable_cache.c @@ -0,0 +1,118 @@ +#include "misc-helper/variable_cache.h" + +#include +#include +#include + +#include +#include "deprecated/unistd_helper.h" + +#include + +typedef struct queue_entry_t { + struct queue_entry *next; + struct queue_entry *prev; +} queue_entry_t; + +/* TODO: add a property or attribute indicate not serialized */ +typedef struct var_entry_t { + queue_entry_t entry_; + char key[128]; + uint64_t value; +} var_entry_t; + +var_entry_t *root = NULL; + +static var_entry_t *cache_get_entry_internal(const char *name) { + var_entry_t *entry; + entry = root; + while (entry != NULL) { + if (strcmp(name, entry->key) == 0) { + return entry; + } + entry = (var_entry_t *)entry->entry_.next; + } + return NULL; +} + +void cache_set(const char *name, uint64_t value) { + var_entry_t *entry = cache_get_entry_internal(name); + if (entry) { + entry->value = value; + return; + } + + entry = (var_entry_t *)malloc(sizeof(var_entry_t)); + strcpy(entry->key, name); + entry->value = value; + + entry->entry_.next = (struct queue_entry *)root; + root = entry; +} + +uint64_t cache_get(const char *name) { + var_entry_t *entry = cache_get_entry_internal(name); + if (entry) { + return entry->value; + } + return 0; +} + +typedef struct entry_block { + int key_length; + int value_length; +} entry_block_t; + +int serialized_to_file(const char *filepath) { + int fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0660); + if (fd == -1) { + printf("open %s failed: %s\n", filepath, strerror(errno)); + return -1; + } + + var_entry_t *entry; + entry = root; + while (entry != NULL) { + entry_block_t block = {0}; + { + block.key_length = strlen(entry->key) + 1; + block.value_length = sizeof(uint64_t); + write(fd, &block, sizeof(block)); + } + + write(fd, entry->key, block.key_length); + write(fd, &entry->value, block.value_length); + + entry = (var_entry_t *)entry->entry_.next; + } + close(fd); + return 0; +} + +int unserialized_from_file(const char *filepath) { + int fd = open(filepath, O_RDONLY); + if (fd == -1) { + printf("open %s failed: %s\n", filepath, strerror(errno)); + return -1; + } + + entry_block_t block = {0}; + while (read(fd, &block, sizeof(block)) > 0) { + char key[128] = {0}; + uint64_t value = 0; + + read(fd, (void *)&key, block.key_length); + read(fd, (void *)&value, block.value_length); + + { + var_entry_t *entry = (var_entry_t *)malloc(sizeof(var_entry_t)); + strcpy(entry->key, key); + entry->value = value; + + entry->entry_.next = (struct queue_entry *)root; + root = entry; + } + } + + return 0; +} diff --git a/app/src/main/cpp/Dobby/external/logging/CMakeLists.txt b/app/src/main/cpp/Dobby/external/logging/CMakeLists.txt new file mode 100644 index 0000000..d83925d --- /dev/null +++ b/app/src/main/cpp/Dobby/external/logging/CMakeLists.txt @@ -0,0 +1,17 @@ +include_directories(.) + +if(NOT BUILDING_KERNEL) + set(SOURCE_FILE_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/cxxlogging.cc + ${CMAKE_CURRENT_SOURCE_DIR}/logging.c + ) +else() + set(SOURCE_FILE_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/cxxlogging.cc + ${CMAKE_CURRENT_SOURCE_DIR}/kernel_logging.c + ) +endif() +add_library(logging + ${SOURCE_FILE_LIST} + ${SOURCE_HEADER_LIST} +) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/external/logging/cxxlogging.cc b/app/src/main/cpp/Dobby/external/logging/cxxlogging.cc new file mode 100644 index 0000000..430b4f9 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/logging/cxxlogging.cc @@ -0,0 +1,36 @@ +#include "logging/cxxlogging.h" + +#if 1 || defined(BUILDING_KERNEL) +void Logger::setLogLevel(LogLevel level) { + log_level_ = level; +} + +void Logger::log(LogLevel level, const char *tag, const char *fmt, ...) { + +} + +void Logger::LogFatal(const char *fmt, ...) { +} +#else +#include +#include +#include +#include + +void Logger::setLogLevel(LogLevel level) { + log_level_ = level; +} + +void Logger::log(LogLevel level, const char *tag, const char *fmt, ...) { + if (level > log_level_) { + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + } +} + +void Logger::LogFatal(const char *fmt, ...) { +} +#endif diff --git a/app/src/main/cpp/Dobby/external/logging/kernel_logging.c b/app/src/main/cpp/Dobby/external/logging/kernel_logging.c new file mode 100644 index 0000000..996f9f9 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/logging/kernel_logging.c @@ -0,0 +1,28 @@ +#include "logging/logging.h" + +#include +#include "utility_macro.h" + +#if defined(BUILDING_KERNEL) +#define abort() +#else +#include +#endif + +static int _log_level = 1; +PUBLIC void log_set_level(int level) { + _log_level = level; +} + +PUBLIC int log_internal_impl(int level, const char *fmt, ...) { + if (level < _log_level) + return 0; + + va_list ap; + va_start(ap, fmt); + + vprintf(fmt, ap); + + va_end(ap); + return 0; +} diff --git a/app/src/main/cpp/Dobby/external/logging/logging.c b/app/src/main/cpp/Dobby/external/logging/logging.c new file mode 100644 index 0000000..2a9ebc7 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/logging/logging.c @@ -0,0 +1,124 @@ +#include "logging/logging.h" + +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#include +#include +#include +#endif + +#if defined(__APPLE__) +#include +#endif + +#if defined(_WIN32) +#define PUBLIC +#else +#define PUBLIC __attribute__((visibility("default"))) +#define INTERNAL __attribute__((visibility("internal"))) +#endif + +static int g_log_level = 1; +static char g_log_tag[64] = {0}; +static bool time_tag_enabled = false; +static bool syslog_enabled = false; +static bool file_log_enabled = false; +static const char *log_file_path = NULL; +static int log_file_fd = -1; +static FILE *log_file_stream = NULL; + +PUBLIC void log_set_level(int level) { + g_log_level = level; +} + +PUBLIC void log_set_tag(const char *tag) { + sprintf(g_log_tag, "[%s] ", tag); +} + +PUBLIC void log_enable_time_tag() { + time_tag_enabled = true; +} + +PUBLIC void log_switch_to_syslog(void) { + syslog_enabled = 1; +} + +PUBLIC void log_switch_to_file(const char *path) { + file_log_enabled = 1; + log_file_path = strdup(path); + log_file_stream = fopen(log_file_path, "w+"); + if (log_file_stream == NULL) { + file_log_enabled = false; + ERROR_LOG("open log file %s failed, %s", path, strerror(errno)); + } +} + +PUBLIC int log_internal_impl(int level, const char *fmt, ...) { + if (level < g_log_level) + return 0; + + char buffer[4096] = {0}; + + if (g_log_tag[0] != 0) { + snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%s ", g_log_tag); + } + + if (time_tag_enabled) { + time_t now = time(NULL); + struct tm *tm = localtime(&now); + snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%04d-%02d-%02d %02d:%02d:%02d ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + } + + snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%s\n", fmt); + + fmt = buffer; + + va_list ap; + va_start(ap, fmt); + +#pragma clang diagnostic ignored "-Wformat" + + if (syslog_enabled) { +#if defined(__APPLE__) + extern void *_os_log_default; + static void (*os_log_with_args)(void *oslog, char type, const char *format, va_list args, void *ret_addr) = 0; + if (!os_log_with_args) + os_log_with_args = (__typeof(os_log_with_args))dlsym((void *)-2, "os_log_with_args"); + os_log_with_args(&_os_log_default, 0x10, fmt, ap, os_log_with_args); +#elif defined(_POSIX_VERSION) + vsyslog(LOG_ERR, fmt, ap); +#endif + } + + if (file_log_enabled) { + char buffer[4096] = {0}; + vsnprintf(buffer, 4096 - 1, fmt, ap); + if (fwrite(buffer, sizeof(char), strlen(buffer) + 1, log_file_stream) == -1) { + file_log_enabled = false; + } + fflush(log_file_stream); + } + + if (!syslog_enabled && !file_log_enabled) { +#if defined(__ANDROID__) +#define ANDROID_LOG_TAG "Dobby" +#include + __android_log_vprint(ANDROID_LOG_INFO, ANDROID_LOG_TAG, fmt, ap); +#else + vprintf(fmt, ap); +#endif + } + +#pragma clang diagnostic warning "-Wformat" + va_end(ap); + return 0; +} diff --git a/app/src/main/cpp/Dobby/external/logging/logging/check_logging.h b/app/src/main/cpp/Dobby/external/logging/logging/check_logging.h new file mode 100644 index 0000000..d13e947 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/logging/logging/check_logging.h @@ -0,0 +1,87 @@ + +#ifndef CHECK_LOGGING_H_ +#define CHECK_LOGGING_H_ + +#include "logging.h" + +#define CHECK_WITH_MSG(condition, message) \ + do { \ + if (!(condition)) { \ + FATAL("Check failed: %s.\n", message); \ + } \ + } while (0) +#define CHECK(condition) CHECK_WITH_MSG(condition, #condition) + +#ifdef LOGGING_DEBUG + +#define DCHECK_WITH_MSG(condition, message) \ + do { \ + if (!(condition)) { \ + FATAL("%s", message); \ + } \ + } while (0) +#define DCHECK(condition) DCHECK_WITH_MSG(condition, #condition) + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use CHECK_EQ et al below. +#define CHECK_OP(name, op, lhs, rhs) \ + do { \ + if (!(lhs op rhs)) { \ + FATAL(" Check failed: %s.\n", #lhs " " #op " " #rhs); \ + } \ + } while (0) + +#define DCHECK_OP(name, op, lhs, rhs) \ + do { \ + if (!((lhs)op(rhs))) { \ + FATAL("%s", ""); \ + } \ + } while (0) + +#else + +// Make all CHECK functions discard their log strings to reduce code +// bloat for official release builds. +#define CHECK_OP(name, op, lhs, rhs) \ + do { \ + bool _cond = lhs op rhs; \ + CHECK_WITH_MSG(_cond, #lhs " " #op " " #rhs "\n"); \ + } while (0) + +#define DCHECK_WITH_MSG(condition, msg) void(0); + +#endif + +#define CHECK_EQ(lhs, rhs) CHECK_OP(EQ, ==, lhs, rhs) +#define CHECK_NE(lhs, rhs) CHECK_OP(NE, !=, lhs, rhs) +#define CHECK_LE(lhs, rhs) CHECK_OP(LE, <=, lhs, rhs) +#define CHECK_LT(lhs, rhs) CHECK_OP(LT, <, lhs, rhs) +#define CHECK_GE(lhs, rhs) CHECK_OP(GE, >=, lhs, rhs) +#define CHECK_GT(lhs, rhs) CHECK_OP(GT, >, lhs, rhs) +#define CHECK_NULL(val) CHECK((val) == NULL) +#define CHECK_NOT_NULL(val) CHECK((val) != NULL) + +#ifdef LOGGING_DEBUG +#define DCHECK_EQ(lhs, rhs) DCHECK_OP(EQ, ==, lhs, rhs) +#define DCHECK_NE(lhs, rhs) DCHECK_OP(NE, !=, lhs, rhs) +#define DCHECK_GT(lhs, rhs) DCHECK_OP(GT, >, lhs, rhs) +#define DCHECK_GE(lhs, rhs) DCHECK_OP(GE, >=, lhs, rhs) +#define DCHECK_LT(lhs, rhs) DCHECK_OP(LT, <, lhs, rhs) +#define DCHECK_LE(lhs, rhs) DCHECK_OP(LE, <=, lhs, rhs) +#define DCHECK_NULL(val) DCHECK((val) == nullptr) +#define DCHECK_NOT_NULL(val) DCHECK((val) != nullptr) +#define DCHECK_IMPLIES(lhs, rhs) DCHECK_WITH_MSG(!(lhs) || (rhs), #lhs " implies " #rhs) +#else +#define DCHECK(condition) ((void)0) +#define DCHECK_EQ(v1, v2) ((void)0) +#define DCHECK_NE(v1, v2) ((void)0) +#define DCHECK_GT(v1, v2) ((void)0) +#define DCHECK_GE(v1, v2) ((void)0) +#define DCHECK_LT(v1, v2) ((void)0) +#define DCHECK_LE(v1, v2) ((void)0) +#define DCHECK_NULL(val) ((void)0) +#define DCHECK_NOT_NULL(val) ((void)0) +#define DCHECK_IMPLIES(v1, v2) ((void)0) +#endif + +#endif diff --git a/app/src/main/cpp/Dobby/external/logging/logging/cxxlogging.h b/app/src/main/cpp/Dobby/external/logging/logging/cxxlogging.h new file mode 100644 index 0000000..e41b149 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/logging/logging/cxxlogging.h @@ -0,0 +1,15 @@ +#pragma once + +#include "logging.h" + +class Logger { +public: + void setLogLevel(LogLevel level); + + void log(LogLevel level, const char *tag, const char *fmt, ...); + + void LogFatal(const char *fmt, ...); + +private: + LogLevel log_level_; +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/external/logging/logging/logging.h b/app/src/main/cpp/Dobby/external/logging/logging/logging.h new file mode 100644 index 0000000..8bf9075 --- /dev/null +++ b/app/src/main/cpp/Dobby/external/logging/logging/logging.h @@ -0,0 +1,88 @@ +#pragma once + +#define LOG_TAG NULL + +typedef enum { + LOG_LEVEL_VERBOSE = 0, + LOG_LEVEL_DEBUG = 1, + LOG_LEVEL_INFO = 2, + LOG_LEVEL_WARN = 3, + LOG_LEVEL_ERROR = 4, + LOG_LEVEL_FATAL = 5 +} LogLevel; + +#if 1 +#ifdef __cplusplus +extern "C" { +#endif + +void log_set_level(int level); + +void log_set_tag(const char *tag); + +void log_enable_time_tag(); + +void log_switch_to_syslog(); + +void log_switch_to_file(const char *path); + +#if !defined(LOG_FUNCTION_IMPL) +#define LOG_FUNCTION_IMPL log_internal_impl +#endif + +int log_internal_impl(int level, const char *, ...); + +#if defined(LOGGING_DISABLE) +#define LOG_FUNCTION_IMPL(...) +#endif + +#ifdef __cplusplus +} +#endif +#else +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif +#endif + +#define RAW_LOG(level, fmt, ...) \ + do { \ + LOG_FUNCTION_IMPL(level, fmt, ##__VA_ARGS__); \ + } while (0) + +#define LOG(level, fmt, ...) \ + do { \ + if (LOG_TAG) \ + LOG_FUNCTION_IMPL(level, "[%s] " fmt, LOG_TAG, ##__VA_ARGS__); \ + else \ + LOG_FUNCTION_IMPL(level, fmt, ##__VA_ARGS__); \ + } while (0) + +#define INFO_LOG(fmt, ...) \ + do { \ + LOG(LOG_LEVEL_INFO, "[*] " fmt, ##__VA_ARGS__); \ + } while (0) + +#define ERROR_LOG(fmt, ...) \ + do { \ + LOG(LOG_LEVEL_ERROR, "[!] [%s:%d:%s]" fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ + } while (0) + +#define FATAL(fmt, ...) \ + do { \ + LOG(LOG_LEVEL_ERROR, "[!] [%s:%d:%s]" fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ + assert(0); \ + } while (0) + +#if defined(LOGGING_DEBUG) +#define DLOG(level, fmt, ...) LOG(level, fmt, ##__VA_ARGS__) +#else +#define DLOG(level, fmt, ...) +#endif + +#define UNIMPLEMENTED() FATAL("%s\n", "unimplemented code!!!") +#define UNREACHABLE() FATAL("%s\n", "unreachable code!!!") \ No newline at end of file diff --git a/app/src/main/cpp/dobby/dobby.h b/app/src/main/cpp/Dobby/include/dobby.h similarity index 64% rename from app/src/main/cpp/dobby/dobby.h rename to app/src/main/cpp/Dobby/include/dobby.h index 484d314..45ec88b 100644 --- a/app/src/main/cpp/dobby/dobby.h +++ b/app/src/main/cpp/Dobby/include/dobby.h @@ -1,152 +1,182 @@ -#ifndef dobby_h -#define dobby_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -typedef uintptr_t addr_t; -typedef uint32_t addr32_t; -typedef uint64_t addr64_t; - -typedef void *dobby_dummy_func_t; -typedef void *asm_func_t; - -#if defined(__arm__) -typedef struct { - uint32_t dummy_0; - uint32_t dummy_1; - - uint32_t dummy_2; - uint32_t sp; - - union { - uint32_t r[13]; - struct { - uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; - } regs; - } general; - - uint32_t lr; -} DobbyRegisterContext; -#elif defined(__arm64__) || defined(__aarch64__) -#define ARM64_TMP_REG_NDX_0 17 - -typedef union _FPReg { - __int128_t q; - struct { - double d1; - double d2; - } d; - struct { - float f1; - float f2; - float f3; - float f4; - } f; -} FPReg; - -// register context -typedef struct { - uint64_t dmmpy_0; // dummy placeholder - uint64_t sp; - - uint64_t dmmpy_1; // dummy placeholder - union { - uint64_t x[29]; - struct { - uint64_t 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; - } regs; - } general; - - uint64_t fp; - uint64_t lr; - - union { - FPReg q[32]; - struct { - FPReg q0, q1, q2, q3, q4, q5, q6, q7; - // [!!! READ ME !!!] - // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack - FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, - q30, q31; - } regs; - } floating; -} DobbyRegisterContext; -#elif defined(_M_IX86) || defined(__i386__) -typedef struct _RegisterContext { - uint32_t dummy_0; - uint32_t esp; - - uint32_t dummy_1; - uint32_t flags; - - union { - struct { - uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi; - } regs; - } general; - -} DobbyRegisterContext; -#elif defined(_M_X64) || defined(__x86_64__) -typedef struct { - uint64_t dummy_0; - uint64_t rsp; - - union { - struct { - uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15; - } regs; - } general; - - uint64_t dummy_1; - uint64_t flags; -} DobbyRegisterContext; -#endif - -#define install_hook_name(name, fn_ret_t, fn_args_t...) \ - static fn_ret_t fake_##name(fn_args_t); \ - static fn_ret_t (*orig_##name)(fn_args_t); \ - /* __attribute__((constructor)) */ static void install_hook_##name(void *sym_addr) { \ - DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \ - return; \ - } \ - fn_ret_t fake_##name(fn_args_t) - -// memory code patch -int DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size); - -// function inline hook -int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func); - -// dynamic binary instruction instrument -// for Arm64, can't access q8 - q31, unless enable full floating-point register pack -typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx); -int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler); - -// destroy and restore code patch -int DobbyDestroy(void *address); - -const char *DobbyGetVersion(); - -// symbol resolver -void *DobbySymbolResolver(const char *image_name, const char *symbol_name); - -// import table replace -int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func, - dobby_dummy_func_t *orig_func); - -// for arm, Arm64, try use b xxx instead of ldr absolute indirect branch -// for x86, x64, always use absolute indirect jump -void dobby_enable_near_branch_trampoline(); -void dobby_disable_near_branch_trampoline(); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef dobby_h +#define dobby_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +void log_set_level(int level); +void log_set_tag(const char *tag); +void log_enable_time_tag(); +void log_switch_to_syslog(); +void log_switch_to_file(const char *path); + +typedef enum { + kMemoryOperationSuccess, + kMemoryOperationError, + kNotSupportAllocateExecutableMemory, + kNotEnough, + kNone +} MemoryOperationError; + +typedef uintptr_t addr_t; +typedef uint32_t addr32_t; +typedef uint64_t addr64_t; +typedef void (*dobby_dummy_func_t)(); +typedef void (*asm_func_t)(); + +MemoryOperationError DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size); + +#if !defined(DISABLE_ARCH_DETECT) +#if defined(__arm__) +#define TARGET_ARCH_ARM 1 +#elif defined(__arm64__) || defined(__aarch64__) +#define TARGET_ARCH_ARM64 1 +#elif defined(_M_IX86) || defined(__i386__) +#define TARGET_ARCH_IA32 1 +#elif defined(_M_X64) || defined(__x86_64__) +#define TARGET_ARCH_X64 1 +#else +#error Target architecture was not detected as supported by Dobby +#endif +#endif + +#if defined(TARGET_ARCH_ARM) +typedef struct { + uint32_t dummy_0; + uint32_t dummy_1; + + uint32_t dummy_2; + uint32_t sp; + + union { + uint32_t r[13]; + struct { + uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; + } regs; + } general; + + uint32_t lr; +} DobbyRegisterContext; +#elif defined(TARGET_ARCH_ARM64) +#define ARM64_TMP_REG_NDX_0 17 + +typedef union _FPReg { + __int128_t q; + struct { + double d1; + double d2; + } d; + struct { + float f1; + float f2; + float f3; + float f4; + } f; +} FPReg; + +// register context +typedef struct { + uint64_t dmmpy_0; // dummy placeholder + uint64_t sp; + + uint64_t dmmpy_1; // dummy placeholder + union { + uint64_t x[29]; + struct { + uint64_t 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; + } regs; + } general; + + uint64_t fp; + uint64_t lr; + + union { + FPReg q[32]; + struct { + FPReg q0, q1, q2, q3, q4, q5, q6, q7; + // [!!! READ ME !!!] + // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack + FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, + q30, q31; + } regs; + } floating; +} DobbyRegisterContext; +#elif defined(TARGET_ARCH_IA32) +typedef struct _RegisterContext { + uint32_t dummy_0; + uint32_t esp; + + uint32_t dummy_1; + uint32_t flags; + + union { + struct { + uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi; + } regs; + } general; + +} DobbyRegisterContext; +#elif defined(TARGET_ARCH_X64) +typedef struct { + uint64_t dummy_0; + uint64_t rsp; + + union { + struct { + uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15; + } regs; + } general; + + uint64_t dummy_1; + uint64_t flags; +} DobbyRegisterContext; +#endif + +#define RT_FAILED -1 +#define RT_SUCCESS 0 +typedef enum { RS_FAILED = -1, RS_SUCCESS = 0 } RetStatus; + +// DobbyWrap <==> DobbyInstrument, so use DobbyInstrument instead of DobbyWrap +#if 0 +// wrap function with pre_call and post_call +typedef void (*PreCallTy)(DobbyRegisterContext *ctx, const InterceptEntry *info); +typedef void (*PostCallTy)(DobbyRegisterContext *ctx, const InterceptEntry *info); +int DobbyWrap(void *function_address, PreCallTy pre_call, PostCallTy post_call); +#endif + +// function inline hook +int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func); + +// dynamic binary instruction instrument +// [!!! READ ME !!!] +// for Arm64, can't access q8 - q31, unless enable full floating-point register pack +typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx); +int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler); + +int DobbyDestroy(void *address); + +const char *DobbyGetVersion(); + +void *DobbySymbolResolver(const char *image_name, const char *symbol_name); + +int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func, + dobby_dummy_func_t *orig_func); + +// [!!! READ ME !!!] +// for arm, Arm64, dobby will try use b xxx instead of ldr absolute indirect branch +// for x64, dobby always use absolute indirect jump +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) +void dobby_enable_near_branch_trampoline(); +void dobby_disable_near_branch_trampoline(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/src/main/cpp/Dobby/scripts/Dockerfile b/app/src/main/cpp/Dobby/scripts/Dockerfile new file mode 100644 index 0000000..149f448 --- /dev/null +++ b/app/src/main/cpp/Dobby/scripts/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:focal + +ARG DEBIAN_FRONTEND='noninteractive' + +RUN apt-key adv --keyserver 'keyserver.ubuntu.com' --recv-key 'C99B11DEB97541F0' && + apt-add-repository -y -u 'https://cli.github.com/packages' && + apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main' + +ADD setup_linux_cross_compile.sh /root/setup_linux_cross_compile.sh +RUN sh /root/setup_linux_cross_compile.sh diff --git a/app/src/main/cpp/Dobby/scripts/platform_builder.py b/app/src/main/cpp/Dobby/scripts/platform_builder.py new file mode 100644 index 0000000..ede9d30 --- /dev/null +++ b/app/src/main/cpp/Dobby/scripts/platform_builder.py @@ -0,0 +1,240 @@ +import os +import pipes +import re +import shutil +import subprocess +import sys +import logging + +import argparse + +platforms = { + "macos": ["x86_64", "arm64", "arm64e"], + "iphoneos": ["arm64", "arm64e"], + "linux": ["x86", "x86_64", "arm", "arm64"], + "android": ["x86", "x86_64", "armeabi-v7a", "arm64-v8a"] +} + + +class PlatformBuilder(object): + cmake_args = list() + cmake_build_type = "Release" + cmake_build_verbose = False + cmake_build_dir = "" + + library_build_type = "static" + + project_dir = "" + output_dir = "" + output_name = "" + + platform = "" + arch = "" + + def __init__(self, project_dir, library_build_type, platform, arch): + self.project_dir = project_dir + self.library_build_type = library_build_type + self.platform = platform + self.arch = arch + + self.cmake_build_dir = f"{self.project_dir}/build/cmake-build-{platform}-{arch}" + self.output_dir = f"{self.project_dir}/build/{platform}/{arch}" + + self.cmake = "cmake" if PlatformBuilder.cmake_dir is None else f"{PlatformBuilder.cmake_dir}/bin/cmake" + self.clang = "clang" if PlatformBuilder.llvm_dir is None else f"{PlatformBuilder.llvm_dir}/bin/clang" + self.clangxx = "clang++" if PlatformBuilder.llvm_dir is None else f"{PlatformBuilder.llvm_dir}/bin/clang++" + + self.setup_common_args() + + def cmake_generate_build_system(self): + cmake_cmd_options = ["-S {}".format(self.project_dir), "-B {}".format(self.cmake_build_dir)] + cmd = [f"{self.cmake}"] + cmake_cmd_options + self.cmake_args + # subprocess.run(cmd, check=True) + cmd_line = " ".join(cmd) + print(cmd_line) + os.system(cmd_line) + + def setup_common_args(self): + self.cmake_args += [f"-DCMAKE_C_COMPILER={self.clang}", f"-DCMAKE_CXX_COMPILER={self.clangxx}"] + + self.cmake_args += ["-DCMAKE_BUILD_TYPE={}".format(self.cmake_build_type)] + + if self.library_build_type == "shared": + self.cmake_args += ["-DDOBBY_GENERATE_SHARED=ON"] + elif self.library_build_type == "static": + self.cmake_args += ["-DDOBBY_GENERATE_SHARED=OFF"] + + def build(self): + subprocess.run(["mkdir", "-p", "{}".format(self.output_dir)], check=True) + self.cmake_generate_build_system() + + subprocess.run(["make", "-j8", "dobby"], cwd=self.cmake_build_dir, check=True) + + os.system(f"mkdir -p {self.output_dir}") + os.system(f"cp {self.cmake_build_dir}/{self.output_name} {self.output_dir}") + + +class WindowsPlatformBuilder(PlatformBuilder): + + def __init__(self, project_dir, library_build_type, platform, arch): + super().__init__(project_dir, library_build_type, platform, arch) + + if self.library_build_type == "shared": + self.output_name = "libdobby.dll" + else: + self.output_name = "libdobby.lib" + + triples = { + "x86": "i686-pc-windows-msvc", + "x64": "x86_64-pc-windows-msvc", + # "arm": "arm-pc-windows-msvc", + "arm64": "arm64-pc-windows-msvc", + } + + # self.cmake_args += ["--target {}".format(triples[arch])] + self.cmake_args += [ + "-DCMAKE_SYSTEM_PROCESSOR={}".format(arch), + ] + + +class LinuxPlatformBuilder(PlatformBuilder): + + def __init__(self, project_dir, library_build_type, arch): + super().__init__(project_dir, library_build_type, "linux", arch) + + if self.library_build_type == "shared": + self.output_name = "libdobby.so" + else: + self.output_name = "libdobby.a" + + targets = { + "x86": "i686-linux-gnu", + "x86_64": "x86_64-linux-gnu", + "arm": "arm-linux-gnueabi", + "aarch64": "aarch64-linux-gnu", + } + + # self.cmake_args += ["--target={}".format(targets[arch])] + self.cmake_args += [ + "-DCMAKE_SYSTEM_NAME=Linux", + "-DCMAKE_SYSTEM_PROCESSOR={}".format(arch), + ] + + +class AndroidPlatformBuilder(PlatformBuilder): + + def __init__(self, android_nkd_dir, project_dir, library_build_type, arch): + super().__init__(project_dir, library_build_type, "android", arch) + + if self.library_build_type == "shared": + self.output_name = "libdobby.so" + else: + self.output_name = "libdobby.a" + + android_api_level = 21 + if arch == "armeabi-v7a" or arch == "x86": + android_api_level = 19 + + self.cmake_args += [ + "-DCMAKE_SYSTEM_NAME=Android", f"-DCMAKE_ANDROID_NDK={android_nkd_dir}", f"-DCMAKE_ANDROID_ARCH_ABI={arch}", + f"-DCMAKE_SYSTEM_VERSION={android_api_level}" + ] + + +class DarwinPlatformBuilder(PlatformBuilder): + + def __init__(self, project_dir, library_build_type, platform, arch): + super().__init__(project_dir, library_build_type, platform, arch) + + self.cmake_args += [ + "-DCMAKE_OSX_ARCHITECTURES={}".format(arch), + "-DCMAKE_SYSTEM_PROCESSOR={}".format(arch), + ] + + if platform == "macos": + self.cmake_args += ["-DCMAKE_SYSTEM_NAME=Darwin"] + elif platform == "iphoneos": + self.cmake_args += ["-DCMAKE_SYSTEM_NAME=iOS", "-DCMAKE_OSX_DEPLOYMENT_TARGET=9.3"] + + if self.library_build_type == "shared": + self.output_name = "libdobby.dylib" + else: + self.output_name = "libdobby.a" + + @classmethod + def lipo_create_fat(cls, project_dir, platform, output_name): + files = list() + archs = platforms[platform] + for arch in archs: + file = f"{project_dir}/build/{platform}/{arch}/{output_name}" + files.append(file) + + cmd = ["lipo", "-create"] + files + ["-output", f"{project_dir}/build/{platform}/{output_name}"] + subprocess.run(cmd, check=True) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--platform", type=str, required=True) + parser.add_argument("--arch", type=str, required=True) + parser.add_argument("--library_build_type", type=str, default="static") + parser.add_argument("--android_ndk_dir", type=str) + parser.add_argument("--cmake_dir", type=str) + parser.add_argument("--llvm_dir", type=str) + args = parser.parse_args() + + logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") + + platform = args.platform + arch = args.arch + library_build_type = args.library_build_type + + PlatformBuilder.cmake_dir = args.cmake_dir + PlatformBuilder.llvm_dir = args.llvm_dir + + project_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + logging.info("project dir: {}".format(project_dir)) + if not os.path.exists(f"{project_dir}/CMakeLists.txt"): + logging.error("Please run this script in Dobby project root directory") + sys.exit(1) + + if platform not in platforms: + logging.error("invalid platform {}".format(platform)) + sys.exit(-1) + + if arch != "all" and arch not in platforms[platform]: + logging.error("invalid arch {} for platform {}".format(arch, platform)) + sys.exit(-1) + + if platform == "android": + if args.android_ndk_dir is None: + logging.error("ndk dir is required for android platform") + sys.exit(-1) + + archs = list() + if arch == "all": + archs = platforms[platform] + else: + archs.append(arch) + logging.info("build platform: {}, archs: {}".format(platform, archs)) + + for arch_ in archs: + if platform == "macos": + builder = DarwinPlatformBuilder(project_dir, library_build_type, platform, arch_) + elif platform == "iphoneos": + builder = DarwinPlatformBuilder(project_dir, library_build_type, platform, arch_) + elif platform == "android": + builder = AndroidPlatformBuilder(args.android_ndk_dir, project_dir, library_build_type, arch_) + elif platform == "linux": + builder = LinuxPlatformBuilder(project_dir, library_build_type, arch_) + else: + logging.error("invalid platform {}".format(platform)) + sys.exit(-1) + logging.info( + f"build platform: {platform}, arch: {arch_}, cmake_build_dir: {builder.cmake_build_dir}, output_dir: {builder.output_dir}" + ) + builder.build() + + if platform in ["iphoneos", "macos"] and arch == "all": + output_name = "libdobby.dylib" if library_build_type == "shared" else "libdobby.a" + DarwinPlatformBuilder.lipo_create_fat(project_dir, platform, output_name) diff --git a/app/src/main/cpp/Dobby/scripts/setup_linux_cross_compile.sh b/app/src/main/cpp/Dobby/scripts/setup_linux_cross_compile.sh new file mode 100644 index 0000000..9900810 --- /dev/null +++ b/app/src/main/cpp/Dobby/scripts/setup_linux_cross_compile.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +# if error, exit +set - + +sudo apt update +sudo apt-get install -y \ + apt-utils \ + build-essential \ + curl \ + wget \ + unzip \ + gcc-multilib \ + make \ + zsh + +mkdir -p ~/opt + +cd ~/opt +CMAKE_VERSION=3.20.2 +CMAKE_DOWNLOAD_PACKAGE=cmake-$CMAKE_VERSION-linux-x86_64 +wget https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/$CMAKE_DOWNLOAD_PACKAGE.tar.gz && + tar -zxf $CMAKE_DOWNLOAD_PACKAGE.tar.gz >/dev/null && + mv $CMAKE_DOWNLOAD_PACKAGE cmake-$CMAKE_VERSION +CMAKE_HOME=~/opt/cmake-$CMAKE_VERSION + +cd ~/opt +LLVM_VERSION=14.0.0 +LLVM_DOWNLOAD_PACKAGE=clang+llvm-$LLVM_VERSION-x86_64-linux-gnu-ubuntu-18.04 +wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/$LLVM_DOWNLOAD_PACKAGE.tar.xz && + tar -xf $LLVM_DOWNLOAD_PACKAGE.tar.xz >/dev/null && + mv $LLVM_DOWNLOAD_PACKAGE llvm-$LLVM_VERSION +LLVM_HOME=~/opt/llvm-$LLVM_VERSION + +cd ~/opt +NDK_VERSION=r25b +NDK_DOWNLOAD_PACKAGE=android-ndk-$NDK_VERSION-linux +NDK_DOWNLOAD_UNZIP_PACKAGE=android-ndk-$NDK_VERSION +wget https://dl.google.com/android/repository/$NDK_DOWNLOAD_PACKAGE.zip && + unzip -q $NDK_DOWNLOAD_PACKAGE.zip >/dev/null && + mv $NDK_DOWNLOAD_UNZIP_PACKAGE ndk-$NDK_VERSION && + rm $NDK_DOWNLOAD_PACKAGE.zip +ANDROID_NDK_HOME=~/opt/android-ndk-$NDK_VERSION diff --git a/app/src/main/cpp/Dobby/scripts/setup_macos_cross_compile.sh b/app/src/main/cpp/Dobby/scripts/setup_macos_cross_compile.sh new file mode 100644 index 0000000..594877b --- /dev/null +++ b/app/src/main/cpp/Dobby/scripts/setup_macos_cross_compile.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# if error, exit +set - + +mkdir -p ~/opt + +cd ~/opt +CMAKE_VERSION=3.20.2 +CMAKE_DOWNLOAD_PACKAGE=cmake-$CMAKE_VERSION-macos-universal +wget https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/$CMAKE_DOWNLOAD_PACKAGE.tar.gz && + tar -zxf $CMAKE_DOWNLOAD_PACKAGE.tar.gz >/dev/null && + mv $CMAKE_DOWNLOAD_PACKAGE cmake-$CMAKE_VERSION +CMAKE_HOME=~/opt/cmake-$CMAKE_VERSION + +cd ~/opt +LLVM_VERSION=14.0.0 +LLVM_DOWNLOAD_PACKAGE=clang+llvm-$LLVM_VERSION-x86_64-apple-darwin +wget https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/$LLVM_DOWNLOAD_PACKAGE.tar.xz && + tar -xf $LLVM_DOWNLOAD_PACKAGE.tar.xz >/dev/null && + mv $LLVM_DOWNLOAD_PACKAGE llvm-$LLVM_VERSION +LLVM_HOME=~/opt/llvm-$LLVM_VERSION diff --git a/app/src/main/cpp/Dobby/source/Backend/KernelMode/ExecMemory/clear-cache-tool-all.c b/app/src/main/cpp/Dobby/source/Backend/KernelMode/ExecMemory/clear-cache-tool-all.c new file mode 100644 index 0000000..495257f --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/KernelMode/ExecMemory/clear-cache-tool-all.c @@ -0,0 +1,3 @@ +void ClearCache(void *start, void *end) { + return; +} diff --git a/app/src/main/cpp/Dobby/source/Backend/KernelMode/ExecMemory/code-patch-tool-darwin.cc b/app/src/main/cpp/Dobby/source/Backend/KernelMode/ExecMemory/code-patch-tool-darwin.cc new file mode 100644 index 0000000..fb807ba --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/KernelMode/ExecMemory/code-patch-tool-darwin.cc @@ -0,0 +1,109 @@ +#include "dobby_internal.h" + +#include "PlatformUnifiedInterface/ExecMemory/ClearCacheTool.h" + +#include +#include +#include +#include + +#undef max +#undef min +#include + +#define DobbySymbolResolverAuth(o_var, name) \ + do { \ + static void *func_ptr = nullptr; \ + if (func_ptr == nullptr) { \ + func_ptr = DobbySymbolResolver(nullptr, name); \ + if (func_ptr) { \ + func_ptr = ptrauth_strip((void *)func_ptr, ptrauth_key_asia); \ + func_ptr = ptrauth_sign_unauthenticated(func_ptr, ptrauth_key_asia, 0); \ + } \ + } \ + o_var = (typeof(o_var))func_ptr; \ + } while (0); + +#define KERN_RETURN_ERROR(kr, failure) \ + do { \ + if (kr != KERN_SUCCESS) { \ + ERROR_LOG("mach error: %d", kr); \ + return failure; \ + } \ + } while (0); + +PUBLIC MemoryOperationError DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size) { + if (address == nullptr || buffer == nullptr || buffer_size == 0) { + FATAL("invalid argument"); + return kMemoryOperationError; + } + + kern_return_t kr; + + { + + paddr_t dst_paddr = pmap_kit_kvtophys(kernel_pmap, (vaddr_t)address); + paddr_t src_paddr = pmap_kit_kvtophys(kernel_pmap, (vaddr_t)buffer); + pmap_kit_bcopy_phys((addr_t)buffer, dst_paddr, buffer_size, cppvPsnk); + LOG(0, "bcopy_phys: src: %p, dst: %p", src_paddr, dst_paddr); + + pmap_kit_kva_to_pte(kernel_pmap, (vaddr_t)address); + pmap_kit_set_perm(kernel_pmap, (vaddr_t)address, (vaddr_t)address + PAGE_SIZE, VM_PROT_READ | VM_PROT_EXECUTE); + + if (memcmp(address, buffer, buffer_size)) + return kMemoryOperationError; + } + + if (0) { + vm_map_t self_task = kernel_map; + + int page_size = PAGE_SIZE; + addr_t page_aligned_address = ALIGN_FLOOR(address, page_size); + int offset = (int)((addr_t)address - page_aligned_address); + + mach_vm_address_t remap_dummy_page = 0; + kr = mach_vm_allocate(self_task, &remap_dummy_page, page_size, VM_FLAGS_ANYWHERE); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + // copy original page + memcpy((void *)remap_dummy_page, (void *)page_aligned_address, page_size); + + // patch buffer + memcpy((void *)(remap_dummy_page + offset), buffer, buffer_size); + + // change permission + kr = mach_vm_protect(self_task, remap_dummy_page, page_size, false, VM_PROT_READ | VM_PROT_EXECUTE); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + static boolean_t (*vm_map_lookup_entry)(vm_map_t map, vm_map_offset_t address, vm_map_entry_t * entry) = nullptr; + if (vm_map_lookup_entry == nullptr) + vm_map_lookup_entry = (typeof(vm_map_lookup_entry))DobbySymbolResolver(nullptr, "_vm_map_lookup_entry"); + + vm_map_entry_t entry; + kr = vm_map_lookup_entry(kernel_map, (vm_map_offset_t)address, &entry); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + struct vm_map_entry_flags { + unsigned int dummy_bits : 17, permanent; + }; + struct vm_map_entry_flags *flags = (typeof(flags))((addr_t)entry + 0x48); + if (flags->permanent) { + flags->permanent = 0; + } + + mach_vm_address_t remap_dest_page = page_aligned_address; + vm_prot_t curr_protection, max_protection; + kr = mach_vm_remap(self_task, &remap_dest_page, page_size, 0, VM_FLAGS_OVERWRITE | VM_FLAGS_FIXED, self_task, + remap_dummy_page, TRUE, &curr_protection, &max_protection, VM_INHERIT_COPY); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + kr = mach_vm_deallocate(self_task, remap_dummy_page, page_size); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + ClearCache(address, (void *)((addr_t)address + buffer_size)); + flush_dcache((vm_offset_t)address, (vm_size_t)buffer_size, 0); + invalidate_icache((vm_offset_t)address, (vm_size_t)buffer_size, 0); + } + + return kMemoryOperationSuccess; +} diff --git a/app/src/main/cpp/Dobby/source/Backend/KernelMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc b/app/src/main/cpp/Dobby/source/Backend/KernelMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc new file mode 100644 index 0000000..94745ed --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/KernelMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc @@ -0,0 +1,131 @@ +#include "PlatformUtil/ProcessRuntimeUtility.h" + +#include + +typedef struct _loaded_kext_summary { + char name[KMOD_MAX_NAME]; + uuid_t uuid; + uint64_t address; + uint64_t size; + uint64_t version; + uint32_t loadTag; + uint32_t flags; + uint64_t reference_list; + uint64_t text_exec_address; + size_t text_exec_size; +} OSKextLoadedKextSummary; +typedef struct _loaded_kext_summary_header { + uint32_t version; + uint32_t entry_size; + uint32_t numSummaries; + uint32_t reserved; /* explicit alignment for gdb */ + OSKextLoadedKextSummary summaries[0]; +} OSKextLoadedKextSummaryHeader; + +#undef min +#undef max +#include +#include + +#include +#if defined(__LP64__) +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +// Generate the name for an offset. +#define KERN_PARAM_OFFSET(type_, member_) __##type_##__##member_##__offset_ +#define KERN_STRUCT_OFFSET KERN_PARAM_OFFSET + +struct vm_map_links { + struct vm_map_entry *prev; + struct vm_map_entry *next; + vm_map_offset_t start; + vm_map_offset_t end; +}; + +struct vm_map_header { + struct vm_map_links links; + uint8_t placeholder_[]; +}; + +static inline vm_map_offset_t vme_start(vm_map_entry_t entry) { + uint KERN_STRUCT_OFFSET(vm_map_entry, links) = 0; + return ((vm_map_header *)((addr_t)entry + KERN_STRUCT_OFFSET(vm_map_entry, links)))->links.start; +} +static inline vm_map_entry_t vm_map_to_entry(vm_map_t map) { + return nullptr; +} +static inline vm_map_entry_t vm_map_first_entry(vm_map_t map) { + uint KERN_STRUCT_OFFSET(vm_map, hdr) = 4; + return ((vm_map_header *)((addr_t)map + KERN_STRUCT_OFFSET(vm_map, hdr)))->links.next; +} + +// --- + +static std::vector regions; +const std::vector &ProcessRuntimeUtility::GetProcessMemoryLayout() { + return regions; +} + +// --- + +#include + +extern "C" void *kernel_info_load_base();; + +std::vector modules; +const std::vector *ProcessRuntimeUtility::GetProcessModuleMap() { + modules.clear(); + + // brute force kernel base ? so rude :) + static void *kernel_base = nullptr; + static OSKextLoadedKextSummaryHeader *_gLoadedKextSummaries = nullptr; + if (kernel_base == nullptr) { + kernel_base = kernel_info_load_base(); + if (kernel_base == nullptr) { + ERROR_LOG("kernel base not found"); + return &modules; + } + LOG(0, "kernel base at: %p", kernel_base); + + extern void *DobbyMachOSymbolResolver(void *header_, const char *symbol_name); + OSKextLoadedKextSummaryHeader **_gLoadedKextSummariesPtr; + _gLoadedKextSummariesPtr = (typeof(_gLoadedKextSummariesPtr))DobbyMachOSymbolResolver(kernel_base, "_gLoadedKextSummaries"); + if (_gLoadedKextSummariesPtr == nullptr) { + ERROR_LOG("failed resolve gLoadedKextSummaries symbol"); + return &modules; + } + _gLoadedKextSummaries = *_gLoadedKextSummariesPtr; + LOG(0, "gLoadedKextSummaries at: %p", _gLoadedKextSummaries); + } + + // only kernel + RuntimeModule module = {0}; + strncpy(module.path, "kernel", sizeof(module.path)); + module.load_address = (void *)kernel_base; + modules.push_back(module); + + // kext + for (int i = 0; i < _gLoadedKextSummaries->numSummaries; ++i) { + strncpy(module.path, _gLoadedKextSummaries->summaries[i].name, sizeof(module.path)); + module.load_address = (void *)_gLoadedKextSummaries->summaries[i].address; + modules.push_back(module); + } + + return &modules; +} + +RuntimeModule ProcessRuntimeUtility::GetProcessModule(const char *name) { + const std::vector *modules = GetProcessModuleMap(); + return RuntimeModule{0}; +} diff --git a/app/src/main/cpp/Dobby/source/Backend/KernelMode/PlatformUtil/ProcessRuntimeUtility.h b/app/src/main/cpp/Dobby/source/Backend/KernelMode/PlatformUtil/ProcessRuntimeUtility.h new file mode 100644 index 0000000..4bd15c4 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/KernelMode/PlatformUtil/ProcessRuntimeUtility.h @@ -0,0 +1,26 @@ +#pragma once + +#include "PlatformUnifiedInterface/MemoryAllocator.h" + +#include "UnifiedInterface/platform.h" + +typedef struct _RuntimeModule { + char path[1024]; + void *load_address; +} RuntimeModule; + +struct MemRegion : MemRange { + MemoryPermission permission; + MemRegion(addr_t addr, size_t size, MemoryPermission perm): MemRange(addr, size), permission(perm) { + + } +}; + +class ProcessRuntimeUtility { +public: + static const std::vector &GetProcessMemoryLayout(); + + static const std::vector *GetProcessModuleMap(); + + static RuntimeModule GetProcessModule(const char *name); +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/exec_mem_placeholder.asm b/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/exec_mem_placeholder.asm new file mode 100644 index 0000000..137da1e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/exec_mem_placeholder.asm @@ -0,0 +1,10 @@ +#include + +#define PAGE_SHIFT 14 +.align PAGE_SHIFT + + .globl EXT(kernel_executable_memory_placeholder) +EXT(kernel_executable_memory_placeholder): +.rept 0x4000/4 +.long 0x41414141 +.endr \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/platform-darwin.cc b/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/platform-darwin.cc new file mode 100644 index 0000000..f0c217d --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/platform-darwin.cc @@ -0,0 +1,106 @@ +#include "UnifiedInterface/platform.h" + +#include +#include +#include +#include + +// ================================================================ +// base :: OSMemory + +static int GetProtectionFromMemoryPermission(MemoryPermission access) { + switch (access) { + case MemoryPermission::kNoAccess: + return PROT_NONE; + case MemoryPermission::kRead: + return PROT_READ; + case MemoryPermission::kReadWrite: + return PROT_READ | PROT_WRITE; + case MemoryPermission::kReadWriteExecute: + return PROT_READ | PROT_WRITE | PROT_EXEC; + case MemoryPermission::kReadExecute: + return PROT_READ | PROT_EXEC; + } + UNREACHABLE(); +} + +int OSMemory::PageSize() { + return static_cast(0x4000); +} + +void *OSMemory::Allocate(size_t size, MemoryPermission access) { + return OSMemory::Allocate(size, access, nullptr); +} + +extern "C" void *kernel_executable_memory_placeholder; +void *OSMemory::Allocate(size_t size, MemoryPermission access, void *fixed_address) { + int prot = GetProtectionFromMemoryPermission(access); + + void *addr = nullptr; + int flags = VM_FLAGS_ANYWHERE; + if (fixed_address != nullptr) { + flags = VM_FLAGS_FIXED; + addr = fixed_address; + } + + // fixme: wire at pmap + if (prot & PROT_EXEC || prot == PROT_NONE) { + addr = &kernel_executable_memory_placeholder; + } else { + kern_return_t ret = mach_vm_allocate(kernel_map, (mach_vm_address_t *)&addr, size, flags); + if (ret != KERN_SUCCESS) { + panic("mach_vm_allocate"); + return nullptr; + } + ret = vm_map_wire(kernel_map, (mach_vm_address_t)addr, (mach_vm_address_t)addr + size, PROT_NONE, false); + if (ret != KERN_SUCCESS) { + panic("vm_map_wire"); + return nullptr; + } + + // make fault before at rw prot + bzero(addr, size); + { memcpy(addr, "AAAAAAAA", 8); } + + if (access == kNoAccess) { + access = kReadExecute; + } + if (!OSMemory::SetPermission((void *)addr, size, access)) { + OSMemory::Free(addr, size); + return nullptr; + } + + { + if (memcmp(addr, "AAAAAAAA", 8) != 0) { + return nullptr; + } + } + } + + return addr; +} + +bool OSMemory::Free(void *address, size_t size) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + auto ret = mach_vm_deallocate(kernel_map, (mach_vm_address_t)address, size); + return ret == KERN_SUCCESS; +} + +bool OSMemory::Release(void *address, size_t size) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + auto ret = mach_vm_deallocate(kernel_map, (mach_vm_address_t)address, size); + return ret == KERN_SUCCESS; +} + +bool OSMemory::SetPermission(void *address, size_t size, MemoryPermission access) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + int prot = GetProtectionFromMemoryPermission(access); + auto ret = mach_vm_protect(kernel_map, (mach_vm_address_t)address, size, false, prot); + return ret == KERN_SUCCESS; +} diff --git a/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/platform.h b/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/platform.h new file mode 100644 index 0000000..723a460 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/KernelMode/UnifiedInterface/platform.h @@ -0,0 +1,26 @@ +#ifndef PLATFORM_INTERFACE_COMMON_PLATFORM_H +#define PLATFORM_INTERFACE_COMMON_PLATFORM_H + +#include "common_header.h" + +// ================================================================ +// base :: OSMemory + +enum MemoryPermission { kNoAccess, kRead, kReadWrite, kReadWriteExecute, kReadExecute }; + +class OSMemory { +public: + static int PageSize(); + + static void *Allocate(size_t size, MemoryPermission access); + + static void *Allocate(size_t size, MemoryPermission access, void *fixed_address); + + static bool Free(void *address, size_t size); + + static bool Release(void *address, size_t size); + + static bool SetPermission(void *address, size_t size, MemoryPermission access); +}; + +#endif diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool-all.c b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool-all.c new file mode 100644 index 0000000..413ef48 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool-all.c @@ -0,0 +1,145 @@ +//===-- clear_cache.c - Implement __clear_cache ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#if __APPLE__ +#include +#endif + +#if defined(_WIN32) +// Forward declare Win32 APIs since the GCC mode driver does not handle the +// newer SDKs as well as needed. +uint32_t FlushInstructionCache(uintptr_t hProcess, void *lpBaseAddress, uintptr_t dwSize); +uintptr_t GetCurrentProcess(void); +#endif + +// The compiler generates calls to __clear_cache() when creating +// trampoline functions on the stack for use with nested functions. +// It is expected to invalidate the instruction cache for the +// specified range. + +void _clear_cache(void *start, void *end) { +#if __i386__ || __x86_64__ || defined(_M_IX86) || defined(_M_X64) +// Intel processors have a unified instruction and data cache +// so there is nothing to do +#elif defined(_WIN32) && (defined(__arm__) || defined(__aarch64__)) + FlushInstructionCache(GetCurrentProcess(), start, end - start); +#elif defined(__arm__) && !defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + struct arm_sync_icache_args arg; + + arg.addr = (uintptr_t)start; + arg.len = (uintptr_t)end - (uintptr_t)start; + + sysarch(ARM_SYNC_ICACHE, &arg); +#elif defined(__linux__) +// We used to include asm/unistd.h for the __ARM_NR_cacheflush define, but +// it also brought many other unused defines, as well as a dependency on +// kernel headers to be installed. +// +// This value is stable at least since Linux 3.13 and should remain so for +// compatibility reasons, warranting it's re-definition here. +#define __ARM_NR_cacheflush 0x0f0002 + register int start_reg __asm("r0") = (int)(intptr_t)start; + const register int end_reg __asm("r1") = (int)(intptr_t)end; + const register int flags __asm("r2") = 0; + const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush; + __asm __volatile("svc 0x0" : "=r"(start_reg) : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags)); + assert(start_reg == 0 && "Cache flush syscall failed."); +#else + compilerrt_abort(); +#endif +#elif defined(__linux__) && defined(__mips__) + const uintptr_t start_int = (uintptr_t)start; + const uintptr_t end_int = (uintptr_t)end; + syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE); +#elif defined(__mips__) && defined(__OpenBSD__) + cacheflush(start, (uintptr_t)end - (uintptr_t)start, BCACHE); +#elif defined(__aarch64__) && !defined(__APPLE__) + uint64_t xstart = (uint64_t)(uintptr_t)start; + uint64_t xend = (uint64_t)(uintptr_t)end; + + // Get Cache Type Info. + static uint64_t ctr_el0 = 0; + if (ctr_el0 == 0) + __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0)); + + // The DC and IC instructions must use 64-bit registers so we don't use + // uintptr_t in case this runs in an IPL32 environment. + uint64_t addr; + + // If CTR_EL0.IDC is set, data cache cleaning to the point of unification + // is not required for instruction to data coherence. + if (((ctr_el0 >> 28) & 0x1) == 0x0) { + const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15); + for (addr = xstart & ~(dcache_line_size - 1); addr < xend; addr += dcache_line_size) + __asm __volatile("dc cvau, %0" ::"r"(addr)); + } + __asm __volatile("dsb ish"); + + // If CTR_EL0.DIC is set, instruction cache invalidation to the point of + // unification is not required for instruction to data coherence. + if (((ctr_el0 >> 29) & 0x1) == 0x0) { + const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15); + for (addr = xstart & ~(icache_line_size - 1); addr < xend; addr += icache_line_size) + __asm __volatile("ic ivau, %0" ::"r"(addr)); + __asm __volatile("dsb ish"); + } + __asm __volatile("isb sy"); +#elif defined(__powerpc64__) + const size_t line_size = 32; + const size_t len = (uintptr_t)end - (uintptr_t)start; + + const uintptr_t mask = ~(line_size - 1); + const uintptr_t start_line = ((uintptr_t)start) & mask; + const uintptr_t end_line = ((uintptr_t)start + len + line_size - 1) & mask; + + for (uintptr_t line = start_line; line < end_line; line += line_size) + __asm__ volatile("dcbf 0, %0" : : "r"(line)); + __asm__ volatile("sync"); + + for (uintptr_t line = start_line; line < end_line; line += line_size) + __asm__ volatile("icbi 0, %0" : : "r"(line)); + __asm__ volatile("isync"); +#elif defined(__sparc__) + const size_t dword_size = 8; + const size_t len = (uintptr_t)end - (uintptr_t)start; + + const uintptr_t mask = ~(dword_size - 1); + const uintptr_t start_dword = ((uintptr_t)start) & mask; + const uintptr_t end_dword = ((uintptr_t)start + len + dword_size - 1) & mask; + + for (uintptr_t dword = start_dword; dword < end_dword; dword += dword_size) + __asm__ volatile("flush %0" : : "r"(dword)); +#elif defined(__riscv) && defined(__linux__) + // See: arch/riscv/include/asm/cacheflush.h, arch/riscv/kernel/sys_riscv.c + register void *start_reg __asm("a0") = start; + const register void *end_reg __asm("a1") = end; + // "0" means that we clear cache for all threads (SYS_RISCV_FLUSH_ICACHE_ALL) + const register long flags __asm("a2") = 0; + const register long syscall_nr __asm("a7") = __NR_riscv_flush_icache; + __asm __volatile("ecall" : "=r"(start_reg) : "r"(start_reg), "r"(end_reg), "r"(flags), "r"(syscall_nr)); + assert(start_reg == 0 && "Cache flush syscall failed."); +#else +#if __APPLE__ + // On Darwin, sys_icache_invalidate() provides this functionality + sys_icache_invalidate(start, end - start); +#elif defined(__ve__) + __asm__ volatile("fencec 2"); +#else + compilerrt_abort(); +#endif +#endif +} + +void ClearCache(void *start, void *end) { + return _clear_cache(start, end); +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool/clear-cache-tool-arm-dummy.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool/clear-cache-tool-arm-dummy.cc new file mode 100644 index 0000000..abe26c4 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool/clear-cache-tool-arm-dummy.cc @@ -0,0 +1,53 @@ +#ifndef USER_MODE_CLEAR_CACHE_TOOL_H +#define USER_MODE_CLEAR_CACHE_TOOL_H + +#include "core/arch/Cpu.h" + +#include "PlatformInterface/globals.h" + +#if !HOST_OS_IOS +#include // for cache flushing. +#endif + +void CpuFeatures::FlushICache(void *startp, void *endp) { + +#if HOST_OS_IOS + // Precompilation never patches code so there should be no I cache flushes. + CpuFeatures::ClearCache(startp, endp); + +#else + + register uint32_t beg asm("r0") = reinterpret_cast(startp); + register uint32_t end asm("r1") = reinterpret_cast(endp); + register uint32_t flg asm("r2") = 0; + +#ifdef __clang__ + // This variant of the asm avoids a constant pool entry, which can be + // problematic when LTO'ing. It is also slightly shorter. + register uint32_t scno asm("r7") = __ARM_NR_cacheflush; + + asm volatile("svc 0\n" : : "r"(beg), "r"(end), "r"(flg), "r"(scno) : "memory"); +#else + // Use a different variant of the asm with GCC because some versions doesn't + // support r7 as an asm input. + asm volatile( + // This assembly works for both ARM and Thumb targets. + + // Preserve r7; it is callee-saved, and GCC uses it as a frame pointer for + // Thumb targets. + " push {r7}\n" + // r0 = beg + // r1 = end + // r2 = flags (0) + " ldr r7, =%c[scno]\n" // r7 = syscall number + " svc 0\n" + + " pop {r7}\n" + : + : "r"(beg), "r"(end), "r"(flg), [scno] "i"(__ARM_NR_cacheflush) + : "memory"); +#endif +#endif +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool/clear-cache-tool-arm64-dummy.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool/clear-cache-tool-arm64-dummy.cc new file mode 100644 index 0000000..60580a5 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/clear-cache-tool/clear-cache-tool-arm64-dummy.cc @@ -0,0 +1,103 @@ +#ifndef USER_MODE_CLEAR_CACHE_TOOL_ARM64_H +#define USER_MODE_CLEAR_CACHE_TOOL_ARM64_H + +#include "core/arch/Cpu.h" + +#include "PlatformInterface/globals.h" + +class CacheLineSizes { +public: + CacheLineSizes() { + // Copy the content of the cache type register to a core register. + __asm__ __volatile__("mrs %x[ctr], ctr_el0" // NOLINT + : [ctr] "=r"(cache_type_register_)); + } + + uint32_t icache_line_size() const { + return ExtractCacheLineSize(0); + } + uint32_t dcache_line_size() const { + return ExtractCacheLineSize(16); + } + +private: + uint32_t ExtractCacheLineSize(int cache_line_size_shift) const { + // The cache type register holds the size of cache lines in words as a + // power of two. + return 4 << ((cache_type_register_ >> cache_line_size_shift) & 0xF); + } + + uint32_t cache_type_register_; +}; + +void CpuFeatures::FlushICache(void *startp, void *endp) { + // The code below assumes user space cache operations are allowed. The goal + // of this routine is to make sure the code generated is visible to the I + // side of the CPU. + +#if HOST_OS_IOS + // Precompilation never patches code so there should be no I cache flushes. + CpuFeatures::ClearCache(startp, endp); +#else + uintptr_t start = reinterpret_cast(startp); + // Sizes will be used to generate a mask big enough to cover a pointer. + CacheLineSizes sizes; + uintptr_t dsize = sizes.dcache_line_size(); + uintptr_t isize = sizes.icache_line_size(); + // Cache line sizes are always a power of 2. + uintptr_t dstart = start & ~(dsize - 1); + uintptr_t istart = start & ~(isize - 1); + uintptr_t end = reinterpret_cast(endp); + + __asm__ __volatile__( // NOLINT + // Clean every line of the D cache containing the target data. + "0: \n\t" + // dc : Data Cache maintenance + // c : Clean + // i : Invalidate + // va : by (Virtual) Address + // c : to the point of Coherency + // See ARM DDI 0406B page B2-12 for more information. + // We would prefer to use "cvau" (clean to the point of unification) here + // but we use "civac" to work around Cortex-A53 errata 819472, 826319, + // 827319 and 824069. + "dc civac, %[dline] \n\t" + "add %[dline], %[dline], %[dsize] \n\t" + "cmp %[dline], %[end] \n\t" + "b.lt 0b \n\t" + // Barrier to make sure the effect of the code above is visible to the rest + // of the world. + // dsb : Data Synchronisation Barrier + // ish : Inner SHareable domain + // The point of unification for an Inner Shareable shareability domain is + // the point by which the instruction and data caches of all the processors + // in that Inner Shareable shareability domain are guaranteed to see the + // same copy of a memory location. See ARM DDI 0406B page B2-12 for more + // information. + "dsb ish \n\t" + // Invalidate every line of the I cache containing the target data. + "1: \n\t" + // ic : instruction cache maintenance + // i : invalidate + // va : by address + // u : to the point of unification + "ic ivau, %[iline] \n\t" + "add %[iline], %[iline], %[isize] \n\t" + "cmp %[iline], %[end] \n\t" + "b.lt 1b \n\t" + // Barrier to make sure the effect of the code above is visible to the rest + // of the world. + "dsb ish \n\t" + // Barrier to ensure any prefetching which happened before this code is + // discarded. + // isb : Instruction Synchronisation Barrier + "isb \n\t" + : [dline] "+r"(dstart), [iline] "+r"(istart) + : [dsize] "r"(dsize), [isize] "r"(isize), [end] "r"(end) + // This code does not write to memory but without the dependency gcc might + // move this code before the code is generated. + : "cc", "memory"); // NOLINT +#endif +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-darwin.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-darwin.cc new file mode 100644 index 0000000..086cf6a --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-darwin.cc @@ -0,0 +1,81 @@ +#include "dobby_internal.h" + +#include "PlatformUnifiedInterface/ExecMemory/ClearCacheTool.h" + +#include + +#include +#include "UnifiedInterface/platform-darwin/mach_vm.h" + +#if defined(__APPLE__) +#include +#include +#endif + +#define KERN_RETURN_ERROR(kr, failure) \ + do { \ + if (kr != KERN_SUCCESS) { \ + ERROR_LOG("mach error: %s", mach_error_string(kr)); \ + return failure; \ + } \ + } while (0); + +PUBLIC MemoryOperationError DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size) { + if (address == nullptr || buffer == nullptr || buffer_size == 0) { + FATAL("invalid argument"); + return kMemoryOperationError; + } + + int page_size = PAGE_SIZE; + addr_t patch_page = ALIGN_FLOOR(address, page_size); + + // cross over page + if ((addr_t)address + buffer_size > patch_page + page_size) { + MemoryOperationError err = kMemoryOperationSuccess; + + void *address_a = address; + uint8_t *buffer_a = buffer; + uint32_t buffer_size_a = (patch_page + page_size - (addr_t)address); + err = DobbyCodePatch(address_a, buffer_a, buffer_size_a); + if (err != kMemoryOperationSuccess) { + return err; + } + + void *address_b = (void *)((addr_t)address + buffer_size_a); + uint8_t *buffer_b = buffer + buffer_size_a; + uint32_t buffer_size_b = buffer_size - buffer_size_a; + err = DobbyCodePatch(address_b, buffer_b, buffer_size_b); + return err; + } + + kern_return_t kr; + vm_map_t self_task = mach_task_self(); + + mach_vm_address_t remap_dummy_page = 0; + kr = mach_vm_allocate(self_task, &remap_dummy_page, page_size, VM_FLAGS_ANYWHERE); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + // copy original page + memcpy((void *)remap_dummy_page, (void *)patch_page, page_size); + + // patch buffer + int offset = (int)((addr_t)address - patch_page); + memcpy((void *)(remap_dummy_page + offset), buffer, buffer_size); + + // change permission + kr = mach_vm_protect(self_task, remap_dummy_page, page_size, false, VM_PROT_READ | VM_PROT_EXECUTE); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + mach_vm_address_t remap_dest_page = patch_page; + vm_prot_t curr_protection, max_protection; + kr = mach_vm_remap(self_task, &remap_dest_page, page_size, 0, VM_FLAGS_OVERWRITE | VM_FLAGS_FIXED, self_task, + remap_dummy_page, TRUE, &curr_protection, &max_protection, VM_INHERIT_COPY); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + kr = mach_vm_deallocate(self_task, remap_dummy_page, page_size); + KERN_RETURN_ERROR(kr, kMemoryOperationError); + + ClearCache(address, (void *)((addr_t)address + buffer_size)); + + return kMemoryOperationSuccess; +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-posix.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-posix.cc new file mode 100644 index 0000000..ccb948b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-posix.cc @@ -0,0 +1,37 @@ + +#include "dobby_internal.h" +#include "core/arch/Cpu.h" + +#include +#include +#include + +#if !defined(__APPLE__) +PUBLIC MemoryOperationError DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size) { +#if defined(__ANDROID__) || defined(__linux__) + int page_size = (int)sysconf(_SC_PAGESIZE); + uintptr_t patch_page = ALIGN_FLOOR(address, page_size); + uintptr_t patch_end_page = ALIGN_FLOOR((uintptr_t)address + buffer_size, page_size); + + // change page permission as rwx + mprotect((void *)patch_page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC); + if (patch_page != patch_end_page) { + mprotect((void *)patch_end_page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC); + } + + // patch buffer + memcpy(address, buffer, buffer_size); + + // restore page permission + mprotect((void *)patch_page, page_size, PROT_READ | PROT_EXEC); + if (patch_page != patch_end_page) { + mprotect((void *)patch_end_page, page_size, PROT_READ | PROT_EXEC); + } + + addr_t clear_start_ = (addr_t)address; + ClearCache((void *)clear_start_, (void *)(clear_start_ + buffer_size)); +#endif + return kMemoryOperationSuccess; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-windows.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-windows.cc new file mode 100644 index 0000000..21ec8e2 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/code-patch-tool-windows.cc @@ -0,0 +1,27 @@ +#include "dobby_internal.h" + +#include + +using namespace zz; + +PUBLIC MemoryOperationError DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size) { + DWORD oldProtect; + int page_size; + + // Get page size + SYSTEM_INFO si; + GetSystemInfo(&si); + page_size = si.dwPageSize; + + void *addressPageAlign = (void *)ALIGN(address, page_size); + + if (!VirtualProtect(addressPageAlign, page_size, PAGE_EXECUTE_READWRITE, &oldProtect)) + return kMemoryOperationError; + + memcpy(address, buffer, buffer_size); + + if (!VirtualProtect(addressPageAlign, page_size, oldProtect, &oldProtect)) + return kMemoryOperationError; + + return kMemoryOperationSuccess; +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/substrated/mach_interface_support/substrated.defs b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/substrated/mach_interface_support/substrated.defs new file mode 100644 index 0000000..f8b1640 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/ExecMemory/substrated/mach_interface_support/substrated.defs @@ -0,0 +1,24 @@ +/* + * Regenerate with: + * + * $(xcrun --sdk macosx -f mig) \ + * -isysroot $(xcrun --sdk macosx --show-sdk-path) \ + * -sheader substratedserver.h \ + * -server substratedserver.c \ + * -header substratedclient.h \ + * -user substratedclient.c \ + * substrated.defs + */ + +subsystem substrated 9000; + +#include +#include + +routine substrated_mark ( + server : mach_port_t; + task : vm_task_entry_t; + source_address : mach_vm_address_t; + source_size : mach_vm_size_t; + inout target_address : mach_vm_address_t +); diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/MultiThreadSupport/ThreadSupport.cpp b/app/src/main/cpp/Dobby/source/Backend/UserMode/MultiThreadSupport/ThreadSupport.cpp new file mode 100644 index 0000000..30be99c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/MultiThreadSupport/ThreadSupport.cpp @@ -0,0 +1,22 @@ +#include "MultiThreadSupport/ThreadSupport.h" + +using namespace zz; + +OSThread::LocalStorageKey ThreadSupport::thread_callstack_key_ = 0; + +// Get current CallStack +CallStack *ThreadSupport::CurrentThreadCallStack() { + + // TODO: __attribute__((destructor)) is better ? + if (!thread_callstack_key_) { + thread_callstack_key_ = OSThread::CreateThreadLocalKey(); + } + + if (OSThread::HasThreadLocal(thread_callstack_key_)) { + return static_cast(OSThread::GetThreadLocal(thread_callstack_key_)); + } else { + CallStack *callstack = new CallStack(); + OSThread::SetThreadLocal(thread_callstack_key_, callstack); + return callstack; + } +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/MultiThreadSupport/ThreadSupport.h b/app/src/main/cpp/Dobby/source/Backend/UserMode/MultiThreadSupport/ThreadSupport.h new file mode 100644 index 0000000..6538d8f --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/MultiThreadSupport/ThreadSupport.h @@ -0,0 +1,63 @@ +#ifndef USER_MODE_MULTI_THREAD_SUPPORT_H +#define USER_MODE_MULTI_THREAD_SUPPORT_H + +#include +#include + +#include "dobby_internal.h" + +#include "source/Backend/UserMode/Thread/PlatformThread.h" + +// StackFrame base in CallStack +typedef struct _StackFrame { + // context between `pre_call` and `post_call` + std::map kv_context; + // origin function ret address + void *orig_ret; +} StackFrame; + +// (thead) CallStack base in thread +typedef struct _CallStack { + std::vector stackframes; +} CallStack; + +// ThreadSupport base on vm_core, support mutipl platforms. +class ThreadSupport { +public: + // Push stack frame + static void PushStackFrame(StackFrame *stackframe) { + CallStack *callstack = ThreadSupport::CurrentThreadCallStack(); + callstack->stackframes.push_back(stackframe); + } + + // Pop stack frame + static StackFrame *PopStackFrame() { + CallStack *callstack = ThreadSupport::CurrentThreadCallStack(); + StackFrame *stackframe = callstack->stackframes.back(); + callstack->stackframes.pop_back(); + return stackframe; + } + + // ===== + static void SetStackFrameContextValue(StackFrame *stackframe, char *key, void *value) { + std::map *kv_context = &stackframe->kv_context; + kv_context->insert(std::pair(key, value)); + }; + + static void *GetStackFrameContextValue(StackFrame *stackframe, char *key) { + std::map kv_context = stackframe->kv_context; + std::map::iterator it; + it = kv_context.find(key); + if (it != kv_context.end()) { + return (void *)it->second; + } + return NULL; + }; + + static CallStack *CurrentThreadCallStack(); + +private: + static zz::OSThread::LocalStorageKey thread_callstack_key_; +}; + +#endif diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc new file mode 100644 index 0000000..07ab59d --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc @@ -0,0 +1,132 @@ +#include "dobby_internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "UnifiedInterface/platform-darwin/mach_vm.h" +#include "PlatformUtil/ProcessRuntimeUtility.h" + +static bool memory_region_comparator(MemRegion a, MemRegion b) { + return (a.start < b.start); +} + +std::vector regions; + +const std::vector &ProcessRuntimeUtility::GetProcessMemoryLayout() { + regions.clear(); + + vm_region_submap_info_64 region_submap_info; + mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + mach_vm_address_t addr = 0; + mach_vm_size_t size = 0; + natural_t depth = 0; + while (true) { + count = VM_REGION_SUBMAP_INFO_COUNT_64; + kern_return_t kr = mach_vm_region_recurse(mach_task_self(), (mach_vm_address_t *)&addr, (mach_vm_size_t *)&size, &depth, (vm_region_recurse_info_t)®ion_submap_info, &count); + if (kr != KERN_SUCCESS) { + if (kr == KERN_INVALID_ADDRESS) { + break; + } else { + break; + } + } + + if (region_submap_info.is_submap) { + depth++; + } else { + MemoryPermission permission; + if ((region_submap_info.protection & PROT_READ) && (region_submap_info.protection & PROT_WRITE)) { + permission = MemoryPermission::kReadWrite; + } else if ((region_submap_info.protection & PROT_READ) == region_submap_info.protection) { + permission = MemoryPermission::kRead; + } else if ((region_submap_info.protection & PROT_READ) && (region_submap_info.protection & PROT_EXEC)) { + permission = MemoryPermission::kReadExecute; + } else { + permission = MemoryPermission::kNoAccess; + } +#if 0 + DLOG(0, "%p --- %p", addr, addr + size); +#endif + MemRegion region = MemRegion(addr, size, permission); + regions.push_back(region); + addr += size; + } + } + + // std::sort(ProcessMemoryLayout.begin(), ProcessMemoryLayout.end(), memory_region_comparator); + + return regions; +} + +static std::vector *modules; + +const std::vector &ProcessRuntimeUtility::GetProcessModuleMap() { + if (modules == nullptr) { + modules = new std::vector(); + } + modules->clear(); + + kern_return_t kr; + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + kr = task_info(mach_task_self_, TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count); + if (kr != KERN_SUCCESS) { + return *modules; + } + + struct dyld_all_image_infos *infos = (struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr; + const struct dyld_image_info *infoArray = infos->infoArray; + uint32_t infoArrayCount = infos->infoArrayCount; + + RuntimeModule module = {0}; + strncpy(module.path, "dummy-placeholder-module", sizeof(module.path)); + module.load_address = 0; + modules->push_back(module); + + for (int i = 0; i < infoArrayCount; ++i) { + const struct dyld_image_info *info = &infoArray[i]; + + { + strncpy(module.path, info->imageFilePath, sizeof(module.path)); + module.load_address = (void *)info->imageLoadAddress; + modules->push_back(module); + } + } + + return *modules; +} + +RuntimeModule ProcessRuntimeUtility::GetProcessModule(const char *name) { + auto modules = GetProcessModuleMap(); + for (auto module : modules) { + if (strstr(module.path, name) != 0) { + return module; + } + } + return RuntimeModule{0}; +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Linux/ProcessRuntimeUtility.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Linux/ProcessRuntimeUtility.cc new file mode 100644 index 0000000..218b8ec --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Linux/ProcessRuntimeUtility.cc @@ -0,0 +1,244 @@ +#include "PlatformUtil/ProcessRuntimeUtility.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define LINE_MAX 2048 + +// ================================================================ +// GetProcessMemoryLayout + +static bool memory_region_comparator(MemRange a, MemRange b) { + return (a.start < b.start); +} + +std::vector regions; +const std::vector &ProcessRuntimeUtility::GetProcessMemoryLayout() { + regions.clear(); + + FILE *fp = fopen("/proc/self/maps", "r"); + if (fp == nullptr) + return regions; + + while (!feof(fp)) { + char line_buffer[LINE_MAX + 1]; + fgets(line_buffer, LINE_MAX, fp); + + // ignore the rest of characters + if (strlen(line_buffer) == LINE_MAX && line_buffer[LINE_MAX] != '\n') { + // Entry not describing executable data. Skip to end of line to set up + // reading the next entry. + int c; + do { + c = getc(fp); + } while ((c != EOF) && (c != '\n')); + if (c == EOF) + break; + } + + addr_t region_start, region_end; + addr_t region_offset; + char permissions[5] = {'\0'}; // Ensure NUL-terminated string. + uint8_t dev_major = 0; + uint8_t dev_minor = 0; + long inode = 0; + int path_index = 0; + + // Sample format from man 5 proc: + // + // address perms offset dev inode pathname + // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm + // + // The final %n term captures the offset in the input string, which is used + // to determine the path name. It *does not* increment the return value. + // Refer to man 3 sscanf for details. + if (sscanf(line_buffer, + "%" PRIxPTR "-%" PRIxPTR " %4c " + "%" PRIxPTR " %hhx:%hhx %ld %n", + ®ion_start, ®ion_end, permissions, ®ion_offset, &dev_major, &dev_minor, &inode, + &path_index) < 7) { + FATAL("/proc/self/maps parse failed!"); + fclose(fp); + return regions; + } + + MemoryPermission permission; + if (permissions[0] == 'r' && permissions[1] == 'w') { + permission = MemoryPermission::kReadWrite; + } else if (permissions[0] == 'r' && permissions[2] == 'x') { + permission = MemoryPermission::kReadExecute; + } else if (permissions[0] == 'r' && permissions[1] == 'w' && permissions[2] == 'x') { + permission = MemoryPermission::kReadWriteExecute; + } else { + permission = MemoryPermission::kNoAccess; + } + +#if 0 + DLOG(0, "%p --- %p", region_start, region_end); +#endif + + MemRegion region = MemRegion(region_start,region_end - region_start, permission); + regions.push_back(region); + } + std::qsort(®ions[0], regions.size(), sizeof(MemRegion), + +[](const void* a, const void* b) -> int { + const auto *i = static_cast(a); + const auto *j = static_cast(b); + if ((addr_t)i->start < (addr_t)j->start) return -1; + if ((addr_t)i->start > (addr_t)j->start) return 1; + return 0; + }); + + fclose(fp); + return regions; +} + +// ================================================================ +// GetProcessModuleMap + +static std::vector *modules; +static std::vector &get_process_map_with_proc_maps() { + if(modules == nullptr) { + modules = new std::vector(); + } + + FILE *fp = fopen("/proc/self/maps", "r"); + if (fp == nullptr) + return *modules; + + while (!feof(fp)) { + char line_buffer[LINE_MAX + 1]; + fgets(line_buffer, LINE_MAX, fp); + + // ignore the rest of characters + if (strlen(line_buffer) == LINE_MAX && line_buffer[LINE_MAX] != '\n') { + // Entry not describing executable data. Skip to end of line to set up + // reading the next entry. + int c; + do { + c = getc(fp); + } while ((c != EOF) && (c != '\n')); + if (c == EOF) + break; + } + + addr_t region_start, region_end; + addr_t region_offset; + char permissions[5] = {'\0'}; // Ensure NUL-terminated string. + uint8_t dev_major = 0; + uint8_t dev_minor = 0; + long inode = 0; + int path_index = 0; + + // Sample format from man 5 proc: + // + // address perms offset dev inode pathname + // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm + // + // The final %n term captures the offset in the input string, which is used + // to determine the path name. It *does not* increment the return value. + // Refer to man 3 sscanf for details. + if (sscanf(line_buffer, + "%" PRIxPTR "-%" PRIxPTR " %4c " + "%" PRIxPTR " %hhx:%hhx %ld %n", + ®ion_start, ®ion_end, permissions, ®ion_offset, &dev_major, &dev_minor, &inode, + &path_index) < 7) { + FATAL("/proc/self/maps parse failed!"); + fclose(fp); + return *modules; + } + + // check header section permission + if (strcmp(permissions, "r--p") != 0 && strcmp(permissions, "r-xp") != 0) + continue; + + // check elf magic number + ElfW(Ehdr) *header = (ElfW(Ehdr) *)region_start; + if (memcmp(header->e_ident, ELFMAG, SELFMAG) != 0) { + continue; + } + + char *path_buffer = line_buffer + path_index; + if (*path_buffer == 0 || *path_buffer == '\n' || *path_buffer == '[') + continue; + RuntimeModule module; + + // strip + if (path_buffer[strlen(path_buffer) - 1] == '\n') { + path_buffer[strlen(path_buffer) - 1] = 0; + } + strncpy(module.path, path_buffer, sizeof(module.path)); + module.load_address = (void *)region_start; + modules->push_back(module); + +#if 0 + DLOG(0, "module: %s", module.path); +#endif + } + + fclose(fp); + return *modules; +} + +#if defined(__LP64__) +static std::vector get_process_map_with_linker_iterator() { + std::vector ProcessModuleMap; + + static int (*dl_iterate_phdr_ptr)(int (*)(struct dl_phdr_info *, size_t, void *), void *); + dl_iterate_phdr_ptr = (__typeof(dl_iterate_phdr_ptr))dlsym(RTLD_DEFAULT, "dl_iterate_phdr"); + if (dl_iterate_phdr_ptr == NULL) { + return ProcessModuleMap; + } + + dl_iterate_phdr_ptr( + [](dl_phdr_info *info, size_t size, void *data) { + RuntimeModule module = {0}; + if (info->dlpi_name && info->dlpi_name[0] == '/') + strcpy(module.path, info->dlpi_name); + + module.load_address = (void *)info->dlpi_addr; + for (size_t i = 0; i < info->dlpi_phnum; ++i) { + if (info->dlpi_phdr[i].p_type == PT_LOAD) { + uintptr_t load_bias = (info->dlpi_phdr[i].p_vaddr - info->dlpi_phdr[i].p_offset); + module.load_address = (void *)((addr_t)module.load_address + load_bias); + break; + } + } + + // push to vector + auto ProcessModuleMap = reinterpret_cast *>(data); + ProcessModuleMap->push_back(module); + return 0; + }, + (void *)&ProcessModuleMap); + + return ProcessModuleMap; +} +#endif + +const std::vector &ProcessRuntimeUtility::GetProcessModuleMap() { +#if defined(__LP64__) && 0 + // TODO: won't resolve main binary + return get_process_map_with_linker_iterator(); +#else + return get_process_map_with_proc_maps(); +#endif +} + +RuntimeModule ProcessRuntimeUtility::GetProcessModule(const char *name) { + auto modules = GetProcessModuleMap(); + for (auto module : modules) { + if (strstr(module.path, name) != 0) { + return module; + } + } + return RuntimeModule{0}; +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/ProcessRuntimeUtility.h b/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/ProcessRuntimeUtility.h new file mode 100644 index 0000000..190c6b1 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/ProcessRuntimeUtility.h @@ -0,0 +1,26 @@ +#pragma once + +#include "PlatformUnifiedInterface/MemoryAllocator.h" + +#include "UnifiedInterface/platform.h" + +typedef struct _RuntimeModule { + char path[1024]; + void *load_address; +} RuntimeModule; + +struct MemRegion : MemRange { + MemoryPermission permission; + + MemRegion(addr_t addr, size_t size, MemoryPermission perm) : MemRange(addr, size), permission(perm) { + } +}; + +class ProcessRuntimeUtility { +public: + static const std::vector &GetProcessMemoryLayout(); + + static const std::vector &GetProcessModuleMap(); + + static RuntimeModule GetProcessModule(const char *name); +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Windows/ProcessRuntimeUtility.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Windows/ProcessRuntimeUtility.cc new file mode 100644 index 0000000..96235b8 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/PlatformUtil/Windows/ProcessRuntimeUtility.cc @@ -0,0 +1,81 @@ +#include "PlatformUtil/ProcessRuntimeUtility.h" + +#include + +#include + +#define LINE_MAX 2048 + +// ================================================================ +// GetProcessMemoryLayout + +static bool memory_region_comparator(MemRange a, MemRange b) { + return (a.address > b.address); +} + +// https://gist.github.com/jedwardsol/9d4fe1fd806043a5767affbd200088ca + +std::vector ProcessMemoryLayout; +std::vector ProcessRuntimeUtility::GetProcessMemoryLayout() { + if (!ProcessMemoryLayout.empty()) { + ProcessMemoryLayout.clear(); + } + + char *address{nullptr}; + MEMORY_BASIC_INFORMATION region; + + while (VirtualQuery(address, ®ion, sizeof(region))) { + address += region.RegionSize; + if (!(region.State & (MEM_COMMIT | MEM_RESERVE))) { + continue; + } + + MemoryPermission permission = MemoryPermission::kNoAccess; + auto mask = PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE; + switch (region.Protect & ~mask) { + case PAGE_NOACCESS: + case PAGE_READONLY: + break; + + case PAGE_EXECUTE: + case PAGE_EXECUTE_READ: + permission = MemoryPermission::kReadExecute; + break; + + case PAGE_READWRITE: + case PAGE_WRITECOPY: + permission = MemoryPermission::kReadWrite; + break; + + case PAGE_EXECUTE_READWRITE: + case PAGE_EXECUTE_WRITECOPY: + permission = MemoryPermission::kReadWriteExecute; + break; + } + + ProcessMemoryLayout.push_back(MemRange{(void *)region.BaseAddress, region.RegionSize, permission}); + } + return ProcessMemoryLayout; +} + +// ================================================================ +// GetProcessModuleMap + +std::vector ProcessModuleMap; + +std::vector ProcessRuntimeUtility::GetProcessModuleMap() { + if (!ProcessMemoryLayout.empty()) { + ProcessMemoryLayout.clear(); + } + return ProcessModuleMap; +} + +RuntimeModule ProcessRuntimeUtility::GetProcessModule(const char *name) { + std::vector ProcessModuleMap = GetProcessModuleMap(); + for (auto module : ProcessModuleMap) { + if (strstr(module.path, name) != 0) { + return module; + } + } + return RuntimeModule{0}; +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/PlatformThread.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/PlatformThread.cc new file mode 100644 index 0000000..827d125 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/PlatformThread.cc @@ -0,0 +1,19 @@ +#include "./PlatformThread.h" + +namespace zz { +int OSThread::GetThreadLocalInt(LocalStorageKey key) { + return static_cast(reinterpret_cast(GetThreadLocal(key))); +} + +void OSThread::SetThreadLocalInt(LocalStorageKey key, int value) { + SetThreadLocal(key, reinterpret_cast(static_cast(value))); +} + +bool OSThread::HasThreadLocal(LocalStorageKey key) { + return GetThreadLocal(key) != nullptr; +} + +void *OSThread::GetExistingThreadLocal(LocalStorageKey key) { + return GetThreadLocal(key); +} +} // namespace zz \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/PlatformThread.h b/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/PlatformThread.h new file mode 100644 index 0000000..ea03091 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/PlatformThread.h @@ -0,0 +1,36 @@ +#ifndef USER_MODE_PLATFORM_THREAD_H +#define USER_MODE_PLATFORM_THREAD_H + +#include "common_header.h" + +namespace zz { + +class OSThread { +public: + typedef int LocalStorageKey; + + static int GetCurrentProcessId(); + + static int GetCurrentThreadId(); + + // Thread-local storage. + static LocalStorageKey CreateThreadLocalKey(); + + static void DeleteThreadLocalKey(LocalStorageKey key); + + static void *GetThreadLocal(LocalStorageKey key); + + static int GetThreadLocalInt(LocalStorageKey key); + + static void SetThreadLocal(LocalStorageKey key, void *value); + + static void SetThreadLocalInt(LocalStorageKey key, int value); + + static bool HasThreadLocal(LocalStorageKey key); + + static void *GetExistingThreadLocal(LocalStorageKey key); +}; + +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/platform-thread-posix.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/platform-thread-posix.cc new file mode 100644 index 0000000..486618c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/platform-thread-posix.cc @@ -0,0 +1,71 @@ +#include "Thread/PlatformThread.h" + +#include // getpid +#include // pthread +#include + +using namespace zz; + +int OSThread::GetCurrentProcessId() { + return static_cast(getpid()); +} + +int OSThread::GetCurrentThreadId() { +#if defined(__APPLE__) + return static_cast(pthread_mach_thread_np(pthread_self())); +#elif defined(__ANDROID__) + return static_cast(gettid()); +#elif defined(__linux__) + return static_cast(syscall(__NR_gettid)); +#else + return static_cast(reinterpret_cast(pthread_self())); +#endif +} + +static OSThread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) { +#if defined(__cygwin__) + // We need to cast pthread_key_t to OSThread::LocalStorageKey in two steps + // because pthread_key_t is a pointer type on Cygwin. This will probably not + // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway. + assert(sizeof(OSThread::LocalStorageKey) == sizeof(pthread_key_t)); + intptr_t ptr_key = reinterpret_cast(pthread_key); + return static_cast(ptr_key); +#else + return static_cast(pthread_key); +#endif +} + +static pthread_key_t LocalKeyToPthreadKey(OSThread::LocalStorageKey local_key) { +#if defined(__cygwin__) + assert(sizeof(OSThread::LocalStorageKey) == sizeof(pthread_key_t)); + intptr_t ptr_key = static_cast(local_key); + return reinterpret_cast(ptr_key); +#else + return static_cast(local_key); +#endif +} + +OSThread::LocalStorageKey OSThread::CreateThreadLocalKey() { + pthread_key_t key; + int result = pthread_key_create(&key, nullptr); + DCHECK_EQ(0, result); + LocalStorageKey local_key = PthreadKeyToLocalKey(key); + return local_key; +} + +void OSThread::DeleteThreadLocalKey(LocalStorageKey key) { + pthread_key_t pthread_key = LocalKeyToPthreadKey(key); + int result = pthread_key_delete(pthread_key); + DCHECK_EQ(0, result); +} + +void *OSThread::GetThreadLocal(LocalStorageKey key) { + pthread_key_t pthread_key = LocalKeyToPthreadKey(key); + return pthread_getspecific(pthread_key); +} + +void OSThread::SetThreadLocal(LocalStorageKey key, void *value) { + pthread_key_t pthread_key = LocalKeyToPthreadKey(key); + int result = pthread_setspecific(pthread_key, value); + DCHECK_EQ(0, result); +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/platform-thread-windows.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/platform-thread-windows.cc new file mode 100644 index 0000000..1428bb0 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/Thread/platform-thread-windows.cc @@ -0,0 +1,25 @@ +#include "PlatformThread.h" + +using namespace zz; + +int OSThread::GetCurrentProcessId() { + return 0; +} + +int OSThread::GetCurrentThreadId() { + return 0; +} + +OSThread::LocalStorageKey OSThread::CreateThreadLocalKey() { + return 0; +} + +void OSThread::DeleteThreadLocalKey(LocalStorageKey key) { +} + +void *OSThread::GetThreadLocal(LocalStorageKey key) { + return NULL; +} + +void OSThread::SetThreadLocal(LocalStorageKey key, void *value) { +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-darwin/mach_vm.h b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-darwin/mach_vm.h new file mode 100644 index 0000000..a9cab32 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-darwin/mach_vm.h @@ -0,0 +1,933 @@ +#ifndef _mach_vm_user_ +#define _mach_vm_user_ + +/* Module mach_vm */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* BEGIN MIG_STRNCPY_ZEROFILL CODE */ + +#if defined(__has_include) +#if __has_include() +#ifndef USING_MIG_STRNCPY_ZEROFILL +#define USING_MIG_STRNCPY_ZEROFILL +#endif +#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ +#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ +#ifdef __cplusplus +extern "C" { +#endif +extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import)); +#ifdef __cplusplus +} +#endif +#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */ +#endif /* __has_include() */ +#endif /* __has_include */ + +/* END MIG_STRNCPY_ZEROFILL CODE */ + +#ifdef AUTOTEST +#ifndef FUNCTION_PTR_T +#define FUNCTION_PTR_T +typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t); +typedef struct { + char *name; + function_ptr_t function; +} function_table_entry; +typedef function_table_entry *function_table_t; +#endif /* FUNCTION_PTR_T */ +#endif /* AUTOTEST */ + +#ifndef mach_vm_MSG_COUNT +#define mach_vm_MSG_COUNT 20 +#endif /* mach_vm_MSG_COUNT */ + +#include +#include +#include +#include + +#ifdef __BeforeMigUserHeader +__BeforeMigUserHeader +#endif /* __BeforeMigUserHeader */ + +#include + + __BEGIN_DECLS + +/* Routine mach_vm_allocate */ +#ifdef mig_external + mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags); + +/* Routine mach_vm_deallocate */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); + +/* Routine mach_vm_protect */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, + vm_prot_t new_protection); + +/* Routine mach_vm_inherit */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_inherit(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_inherit_t new_inheritance); + +/* Routine mach_vm_read */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, + mach_msg_type_number_t *dataCnt); + +/* Routine mach_vm_read_list */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_read_list(vm_map_t target_task, mach_vm_read_entry_t data_list, natural_t count); + +/* Routine mach_vm_write */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt); + +/* Routine mach_vm_copy */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_copy(vm_map_t target_task, mach_vm_address_t source_address, mach_vm_size_t size, + mach_vm_address_t dest_address); + +/* Routine mach_vm_read_overwrite */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, + mach_vm_size_t *outsize); + +/* Routine mach_vm_msync */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_msync(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_sync_t sync_flags); + +/* Routine mach_vm_behavior_set */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_behavior_set(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, + vm_behavior_t new_behavior); + +/* Routine mach_vm_map */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_map(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t size, mach_vm_offset_t mask, int flags, + mem_entry_name_port_t object, memory_object_offset_t offset, boolean_t copy, vm_prot_t curr_protection, + vm_prot_t max_protection, vm_inherit_t inheritance); + +/* Routine mach_vm_machine_attribute */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_machine_attribute(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, + vm_machine_attribute_t attribute, vm_machine_attribute_val_t *value); + +/* Routine mach_vm_remap */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_remap(vm_map_t target_task, mach_vm_address_t *target_address, mach_vm_size_t size, mach_vm_offset_t mask, + int flags, vm_map_t src_task, mach_vm_address_t src_address, boolean_t copy, + vm_prot_t *curr_protection, vm_prot_t *max_protection, vm_inherit_t inheritance); + +/* Routine mach_vm_page_query */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_page_query(vm_map_t target_map, mach_vm_offset_t offset, integer_t *disposition, integer_t *ref_count); + +/* Routine mach_vm_region_recurse */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_region_recurse(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, + natural_t *nesting_depth, vm_region_recurse_info_t info, mach_msg_type_number_t *infoCnt); + +/* Routine mach_vm_region */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_region(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, + vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name); + +/* Routine _mach_make_memory_entry */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + _mach_make_memory_entry(vm_map_t target_task, memory_object_size_t *size, memory_object_offset_t offset, + vm_prot_t permission, mem_entry_name_port_t *object_handle, + mem_entry_name_port_t parent_handle); + +/* Routine mach_vm_purgable_control */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_purgable_control(vm_map_t target_task, mach_vm_address_t address, vm_purgable_t control, int *state); + +/* Routine mach_vm_page_info */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ + kern_return_t + mach_vm_page_info(vm_map_t target_task, mach_vm_address_t address, vm_page_info_flavor_t flavor, + vm_page_info_t info, mach_msg_type_number_t *infoCnt); + +__END_DECLS + +/********************** Caution **************************/ +/* The following data types should be used to calculate */ +/* maximum message sizes only. The actual message may be */ +/* smaller, and the position of the arguments within the */ +/* message layout may vary from what is presented here. */ +/* For example, if any of the arguments are variable- */ +/* sized, and less than the maximum is sent, the data */ +/* will be packed tight in the actual message to reduce */ +/* the presence of holes. */ +/********************** Caution **************************/ + +/* typedefs for all requests */ + +#ifndef __Request__mach_vm_subsystem__defined +#define __Request__mach_vm_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + int flags; +} __Request__mach_vm_allocate_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; +} __Request__mach_vm_deallocate_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + boolean_t set_maximum; + vm_prot_t new_protection; +} __Request__mach_vm_protect_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + vm_inherit_t new_inheritance; +} __Request__mach_vm_inherit_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; +} __Request__mach_vm_read_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_read_entry_t data_list; + natural_t count; +} __Request__mach_vm_read_list_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_ool_descriptor_t data; + /* end of the kernel processed data */ + NDR_record_t NDR; + mach_vm_address_t address; + mach_msg_type_number_t dataCnt; +} __Request__mach_vm_write_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t source_address; + mach_vm_size_t size; + mach_vm_address_t dest_address; +} __Request__mach_vm_copy_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + mach_vm_address_t data; +} __Request__mach_vm_read_overwrite_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + vm_sync_t sync_flags; +} __Request__mach_vm_msync_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + vm_behavior_t new_behavior; +} __Request__mach_vm_behavior_set_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t object; + /* end of the kernel processed data */ + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + mach_vm_offset_t mask; + int flags; + memory_object_offset_t offset; + boolean_t copy; + vm_prot_t curr_protection; + vm_prot_t max_protection; + vm_inherit_t inheritance; +} __Request__mach_vm_map_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + vm_machine_attribute_t attribute; + vm_machine_attribute_val_t value; +} __Request__mach_vm_machine_attribute_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t src_task; + /* end of the kernel processed data */ + NDR_record_t NDR; + mach_vm_address_t target_address; + mach_vm_size_t size; + mach_vm_offset_t mask; + int flags; + mach_vm_address_t src_address; + boolean_t copy; + vm_inherit_t inheritance; +} __Request__mach_vm_remap_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_offset_t offset; +} __Request__mach_vm_page_query_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + natural_t nesting_depth; + mach_msg_type_number_t infoCnt; +} __Request__mach_vm_region_recurse_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + vm_region_flavor_t flavor; + mach_msg_type_number_t infoCnt; +} __Request__mach_vm_region_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t parent_handle; + /* end of the kernel processed data */ + NDR_record_t NDR; + memory_object_size_t size; + memory_object_offset_t offset; + vm_prot_t permission; +} __Request___mach_make_memory_entry_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + vm_purgable_t control; + int state; +} __Request__mach_vm_purgable_control_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + mach_vm_address_t address; + vm_page_info_flavor_t flavor; + mach_msg_type_number_t infoCnt; +} __Request__mach_vm_page_info_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Request__mach_vm_subsystem__defined */ + +/* union of all requests */ + +#ifndef __RequestUnion__mach_vm_subsystem__defined +#define __RequestUnion__mach_vm_subsystem__defined +union __RequestUnion__mach_vm_subsystem { + __Request__mach_vm_allocate_t Request_mach_vm_allocate; + __Request__mach_vm_deallocate_t Request_mach_vm_deallocate; + __Request__mach_vm_protect_t Request_mach_vm_protect; + __Request__mach_vm_inherit_t Request_mach_vm_inherit; + __Request__mach_vm_read_t Request_mach_vm_read; + __Request__mach_vm_read_list_t Request_mach_vm_read_list; + __Request__mach_vm_write_t Request_mach_vm_write; + __Request__mach_vm_copy_t Request_mach_vm_copy; + __Request__mach_vm_read_overwrite_t Request_mach_vm_read_overwrite; + __Request__mach_vm_msync_t Request_mach_vm_msync; + __Request__mach_vm_behavior_set_t Request_mach_vm_behavior_set; + __Request__mach_vm_map_t Request_mach_vm_map; + __Request__mach_vm_machine_attribute_t Request_mach_vm_machine_attribute; + __Request__mach_vm_remap_t Request_mach_vm_remap; + __Request__mach_vm_page_query_t Request_mach_vm_page_query; + __Request__mach_vm_region_recurse_t Request_mach_vm_region_recurse; + __Request__mach_vm_region_t Request_mach_vm_region; + __Request___mach_make_memory_entry_t Request__mach_make_memory_entry; + __Request__mach_vm_purgable_control_t Request_mach_vm_purgable_control; + __Request__mach_vm_page_info_t Request_mach_vm_page_info; +}; +#endif /* !__RequestUnion__mach_vm_subsystem__defined */ +/* typedefs for all replies */ + +#ifndef __Reply__mach_vm_subsystem__defined +#define __Reply__mach_vm_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_vm_address_t address; +} __Reply__mach_vm_allocate_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; +} __Reply__mach_vm_deallocate_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; +} __Reply__mach_vm_protect_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; +} __Reply__mach_vm_inherit_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_ool_descriptor_t data; + /* end of the kernel processed data */ + NDR_record_t NDR; + mach_msg_type_number_t dataCnt; +} __Reply__mach_vm_read_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_vm_read_entry_t data_list; +} __Reply__mach_vm_read_list_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; +} __Reply__mach_vm_write_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; +} __Reply__mach_vm_copy_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_vm_size_t outsize; +} __Reply__mach_vm_read_overwrite_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; +} __Reply__mach_vm_msync_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; +} __Reply__mach_vm_behavior_set_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_vm_address_t address; +} __Reply__mach_vm_map_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + vm_machine_attribute_val_t value; +} __Reply__mach_vm_machine_attribute_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_vm_address_t target_address; + vm_prot_t curr_protection; + vm_prot_t max_protection; +} __Reply__mach_vm_remap_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + integer_t disposition; + integer_t ref_count; +} __Reply__mach_vm_page_query_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_vm_address_t address; + mach_vm_size_t size; + natural_t nesting_depth; + mach_msg_type_number_t infoCnt; + int info[19]; +} __Reply__mach_vm_region_recurse_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t object_name; + /* end of the kernel processed data */ + NDR_record_t NDR; + mach_vm_address_t address; + mach_vm_size_t size; + mach_msg_type_number_t infoCnt; + int info[10]; +} __Reply__mach_vm_region_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t object_handle; + /* end of the kernel processed data */ + NDR_record_t NDR; + memory_object_size_t size; +} __Reply___mach_make_memory_entry_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int state; +} __Reply__mach_vm_purgable_control_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif +typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_msg_type_number_t infoCnt; + int info[32]; +} __Reply__mach_vm_page_info_t __attribute__((unused)); +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Reply__mach_vm_subsystem__defined */ + +/* union of all replies */ + +#ifndef __ReplyUnion__mach_vm_subsystem__defined +#define __ReplyUnion__mach_vm_subsystem__defined +union __ReplyUnion__mach_vm_subsystem { + __Reply__mach_vm_allocate_t Reply_mach_vm_allocate; + __Reply__mach_vm_deallocate_t Reply_mach_vm_deallocate; + __Reply__mach_vm_protect_t Reply_mach_vm_protect; + __Reply__mach_vm_inherit_t Reply_mach_vm_inherit; + __Reply__mach_vm_read_t Reply_mach_vm_read; + __Reply__mach_vm_read_list_t Reply_mach_vm_read_list; + __Reply__mach_vm_write_t Reply_mach_vm_write; + __Reply__mach_vm_copy_t Reply_mach_vm_copy; + __Reply__mach_vm_read_overwrite_t Reply_mach_vm_read_overwrite; + __Reply__mach_vm_msync_t Reply_mach_vm_msync; + __Reply__mach_vm_behavior_set_t Reply_mach_vm_behavior_set; + __Reply__mach_vm_map_t Reply_mach_vm_map; + __Reply__mach_vm_machine_attribute_t Reply_mach_vm_machine_attribute; + __Reply__mach_vm_remap_t Reply_mach_vm_remap; + __Reply__mach_vm_page_query_t Reply_mach_vm_page_query; + __Reply__mach_vm_region_recurse_t Reply_mach_vm_region_recurse; + __Reply__mach_vm_region_t Reply_mach_vm_region; + __Reply___mach_make_memory_entry_t Reply__mach_make_memory_entry; + __Reply__mach_vm_purgable_control_t Reply_mach_vm_purgable_control; + __Reply__mach_vm_page_info_t Reply_mach_vm_page_info; +}; +#endif /* !__RequestUnion__mach_vm_subsystem__defined */ + +#ifndef subsystem_to_name_map_mach_vm +#define subsystem_to_name_map_mach_vm \ + {"mach_vm_allocate", 4800}, {"mach_vm_deallocate", 4801}, {"mach_vm_protect", 4802}, {"mach_vm_inherit", 4803}, \ + {"mach_vm_read", 4804}, {"mach_vm_read_list", 4805}, {"mach_vm_write", 4806}, {"mach_vm_copy", 4807}, \ + {"mach_vm_read_overwrite", 4808}, {"mach_vm_msync", 4809}, {"mach_vm_behavior_set", 4810}, \ + {"mach_vm_map", 4811}, {"mach_vm_machine_attribute", 4812}, {"mach_vm_remap", 4813}, \ + {"mach_vm_page_query", 4814}, {"mach_vm_region_recurse", 4815}, {"mach_vm_region", 4816}, \ + {"_mach_make_memory_entry", 4817}, {"mach_vm_purgable_control", 4818}, { \ + "mach_vm_page_info", 4819 \ + } +#endif + +#ifdef __AfterMigUserHeader +__AfterMigUserHeader +#endif /* __AfterMigUserHeader */ + +#endif /* _mach_vm_user_ */ diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-posix.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-posix.cc new file mode 100644 index 0000000..00cab99 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-posix.cc @@ -0,0 +1,205 @@ +#include +#include +#include +#include + +#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#include // for pthread_set_name_np +#endif + +#include // for sched_yield +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#include // NOLINT, for sysctl +#endif + +#include "logging/logging.h" +#include "logging/check_logging.h" +#include "UnifiedInterface/platform.h" + +#if defined(__APPLE__) +#include +#include +#include +#endif + +#if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT) +#define ANDROID_LOG_TAG "Dobby" + +#include + +#endif + +#include + +#if defined(__APPLE__) +const int kMmapFd = VM_MAKE_TAG(255); +#else +const int kMmapFd = -1; +#endif + +const int kMmapFdOffset = 0; + +// ================================================================ +// base :: Thread + +using namespace base; + +typedef struct thread_handle_t { + pthread_t thread; +} thread_handle_t; + +void ThreadInterface::SetName(const char *name) { +#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) + pthread_set_name_np(pthread_self(), name); +#elif defined(__APPLE__) + pthread_setname_np(name); +#endif +} + +int ThreadInterface::CurrentId() { +#if defined(__APPLE__) + mach_port_t port = mach_thread_self(); + mach_port_deallocate(mach_task_self(), port); + return port; +#elif defined(_POSIX_VERSION) + return syscall(__NR_gettid); +#endif +} + +static void *thread_handler_wrapper(void *ctx) { + ThreadInterface::Delegate *d = (ThreadInterface::Delegate *)ctx; + d->ThreadMain(); + return nullptr; +} + +bool ThreadInterface::Create(ThreadInterface::Delegate *delegate, ThreadHandle *handle) { + thread_handle_t *handle_impl = new thread_handle_t; + + int err = 0; + err = pthread_create(&(handle_impl->thread), nullptr, thread_handler_wrapper, delegate); + if (err != 0) { + FATAL("pthread create failed"); + return false; + } + return true; +} + +Thread::Thread(const char *name) { + strncpy(name_, name, sizeof(name_)); +} + +bool Thread::Start() { + if (ThreadInterface::Create(this, &handle_) == false) { + return false; + } + return true; +} + +// --- OSMemory + +static int GetProtectionFromMemoryPermission(MemoryPermission access) { + switch (access) { + case MemoryPermission::kNoAccess: + return PROT_NONE; + case MemoryPermission::kRead: + return PROT_READ; + case MemoryPermission::kReadWrite: + return PROT_READ | PROT_WRITE; + case MemoryPermission::kReadWriteExecute: + return PROT_READ | PROT_WRITE | PROT_EXEC; + case MemoryPermission::kReadExecute: + return PROT_READ | PROT_EXEC; + } + UNREACHABLE(); +} + +int OSMemory::PageSize() { + return static_cast(sysconf(_SC_PAGESIZE)); +} + +void *OSMemory::Allocate(size_t size, MemoryPermission access) { + return OSMemory::Allocate(size, access, nullptr); +} + +void *OSMemory::Allocate(size_t size, MemoryPermission access, void *fixed_address) { + int prot = GetProtectionFromMemoryPermission(access); + + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + if (fixed_address != nullptr) { + flags = flags | MAP_FIXED; + } + void *result = mmap(fixed_address, size, prot, flags, kMmapFd, kMmapFdOffset); + if (result == MAP_FAILED) + return nullptr; + + return result; +} + +bool OSMemory::Free(void *address, size_t size) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + return munmap(address, size) == 0; +} + +bool OSMemory::Release(void *address, size_t size) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + return munmap(address, size) == 0; +} + +bool OSMemory::SetPermission(void *address, size_t size, MemoryPermission access) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + int prot = GetProtectionFromMemoryPermission(access); + int ret = mprotect(address, size, prot); + if (ret) { + ERROR_LOG("OSMemory::SetPermission: %s\n", ((const char *)strerror(errno))); + } + + return ret == 0; +} + +// --- OSPrint + +void OSPrint::Print(const char *format, ...) { + va_list args; + va_start(args, format); + VPrint(format, args); + va_end(args); +} + +void OSPrint::VPrint(const char *format, va_list args) { +#if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT) + __android_log_vprint(ANDROID_LOG_INFO, ANDROID_LOG_TAG, format, args); +#else + vprintf(format, args); +#endif +} + +void OSPrint::PrintError(const char *format, ...) { + va_list args; + va_start(args, format); + VPrintError(format, args); + va_end(args); +} + +void OSPrint::VPrintError(const char *format, va_list args) { +#if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT) + __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); +#else + vfprintf(stderr, format, args); +#endif +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-windows.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-windows.cc new file mode 100644 index 0000000..ef23325 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform-windows.cc @@ -0,0 +1,87 @@ +#include + +#include + + +#include "logging/logging.h" +#include "logging/check_logging.h" +#include "UnifiedInterface/platform.h" + +int GetProtectionFromMemoryPermission(MemoryPermission access) { + if (kReadWriteExecute == access) + return PAGE_EXECUTE_READWRITE; + else if (kReadExecute == access) + return PAGE_EXECUTE_READ; +} + +int OSMemory::AllocPageSize() { + static int lastRet = -1; + if (lastRet == -1) { + SYSTEM_INFO si; + GetSystemInfo(&si); + lastRet = si.dwAllocationGranularity; // should be used with VirtualAlloc(MEM_RESERVE) + } + return lastRet; +} + +int OSMemory::PageSize() { + static int lastRet = -1; + if (lastRet == -1) { + SYSTEM_INFO si; + GetSystemInfo(&si); + lastRet = si.dwPageSize; // should be used with VirtualAlloc(MEM_RESERVE) + } + return lastRet; +} + +void *OSMemory::Allocate(void *address, int size, MemoryPermission access) { + DCHECK_EQ(0, reinterpret_cast(address) % AllocPageSize()); + DCHECK_EQ(0, size % PageSize()); + + void *result = VirtualAlloc(address, size, MEM_COMMIT | MEM_RESERVE, PAGE_NOACCESS); + OSMemory::SetPermission(result, size, kReadWriteExecute); + if (result == nullptr) + return nullptr; + + // TODO: if need align + void *aligned_base = result; + return static_cast(aligned_base); +} + +// static +bool OSMemory::Free(void *address, const int size) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + return VirtualFree(address, size, MEM_RELEASE); +} + +bool OSMemory::Release(void *address, int size) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + return OSMemory::Free(address, size); +} + +bool OSMemory::SetPermission(void *address, int size, MemoryPermission access) { + DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); + DCHECK_EQ(0, size % PageSize()); + + int prot = GetProtectionFromMemoryPermission(access); + + DWORD oldProtect; + return VirtualProtect(address, size, prot, &oldProtect); +} + +// ===== + +void OSPrint::Print(const char *format, ...) { + va_list args; + va_start(args, format); + VPrint(format, args); + va_end(args); +} + +void OSPrint::VPrint(const char *format, va_list args) { + vprintf(format, args); +} diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform.h b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform.h new file mode 100644 index 0000000..f54ddc9 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/platform.h @@ -0,0 +1,109 @@ +#ifndef PLATFORM_INTERFACE_COMMON_PLATFORM_H +#define PLATFORM_INTERFACE_COMMON_PLATFORM_H + +#include +#include + +namespace base { +// ================================================================ +// base :: ThreadLocalStorageInterface + +class ThreadLocalStorageInterface { + using LocalStorageKey = int32_t; + + // Thread-local storage. + static LocalStorageKey CreateThreadLocalKey(); + + static void DeleteThreadLocalKey(LocalStorageKey key); + + static void *GetThreadLocal(LocalStorageKey key); + + static int GetThreadLocalInt(LocalStorageKey key) { + return static_cast(reinterpret_cast(GetThreadLocal(key))); + } + + static void SetThreadLocal(LocalStorageKey key, void *value); + + static void SetThreadLocalInt(LocalStorageKey key, int value) { + SetThreadLocal(key, reinterpret_cast(static_cast(value))); + } + + static bool HasThreadLocal(LocalStorageKey key) { + return GetThreadLocal(key) != nullptr; + } +}; + +// ================================================================ +// base :: Thread + +typedef void *ThreadHandle; + +class ThreadInterface { +public: + class Delegate { + public: + virtual void ThreadMain() = 0; + }; + +public: + static bool Create(Delegate *delegate, ThreadHandle *handle); + + static int CurrentId(); + + static void SetName(const char *); +}; + +class Thread : public ThreadInterface, public ThreadInterface::Delegate { +public: + Thread(const char *name); + + bool Start(); + +private: + ThreadHandle handle_; + + char name_[256]; +}; +} // namespace base + +// ================================================================ +// base :: OSMemory + +enum MemoryPermission { kNoAccess, kRead, kReadWrite, kReadWriteExecute, kReadExecute }; + +class OSMemory { +public: + static int PageSize(); + + static void *Allocate(size_t size, MemoryPermission access); + + static void *Allocate(size_t size, MemoryPermission access, void *fixed_address); + + static bool Free(void *address, size_t size); + + static bool Release(void *address, size_t size); + + static bool SetPermission(void *address, size_t size, MemoryPermission access); +}; + +// ================================================================ +// base :: OSPrint + +class OSPrint { +public: + // Print output to console. This is mostly used for debugging output. + // On platforms that has standard terminal output, the output + // should go to stdout. + static void Print(const char *format, ...); + + static void VPrint(const char *format, va_list args); + + // Print error output to console. This is mostly used for error message + // output. On platforms that has standard terminal output, the output + // should go to stderr. + static void PrintError(const char *format, ...); + + static void VPrintError(const char *format, va_list args); +}; + +#endif diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/semaphore.cc b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/semaphore.cc new file mode 100644 index 0000000..12a15e0 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/semaphore.cc @@ -0,0 +1,160 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/base/platform/semaphore.h" + +#if V8_OS_MACOSX +#include +#endif + +#include + +#include "src/base/logging.h" +#include "src/base/platform/elapsed-timer.h" +#include "src/base/platform/time.h" + +namespace v8 { +namespace base { + +#if V8_OS_MACOSX + +Semaphore::Semaphore(int count) { + native_handle_ = dispatch_semaphore_create(count); + DCHECK(native_handle_); +} + +Semaphore::~Semaphore() { + dispatch_release(native_handle_); +} + +void Semaphore::Signal() { + dispatch_semaphore_signal(native_handle_); +} + +void Semaphore::Wait() { + dispatch_semaphore_wait(native_handle_, DISPATCH_TIME_FOREVER); +} + +bool Semaphore::WaitFor(const TimeDelta &rel_time) { + dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, rel_time.InNanoseconds()); + return dispatch_semaphore_wait(native_handle_, timeout) == 0; +} + +#elif V8_OS_POSIX + +Semaphore::Semaphore(int count) { + DCHECK_GE(count, 0); + int result = sem_init(&native_handle_, 0, count); + DCHECK_EQ(0, result); + USE(result); +} + +Semaphore::~Semaphore() { + int result = sem_destroy(&native_handle_); + DCHECK_EQ(0, result); + USE(result); +} + +void Semaphore::Signal() { + int result = sem_post(&native_handle_); + // This check may fail with 0) { + // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1. + errno = result; + result = -1; + } +#endif + if (result == -1 && errno == ETIMEDOUT) { + // Timed out while waiting for semaphore. + return false; + } + // Signal caused spurious wakeup. + DCHECK_EQ(-1, result); + DCHECK_EQ(EINTR, errno); + } +} + +#elif V8_OS_WIN + +Semaphore::Semaphore(int count) { + DCHECK_GE(count, 0); + native_handle_ = ::CreateSemaphoreA(nullptr, count, 0x7FFFFFFF, nullptr); + DCHECK_NOT_NULL(native_handle_); +} + +Semaphore::~Semaphore() { + BOOL result = CloseHandle(native_handle_); + DCHECK(result); + USE(result); +} + +void Semaphore::Signal() { + LONG dummy; + BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy); + DCHECK(result); + USE(result); +} + +void Semaphore::Wait() { + DWORD result = WaitForSingleObject(native_handle_, INFINITE); + DCHECK(result == WAIT_OBJECT_0); + USE(result); +} + +bool Semaphore::WaitFor(const TimeDelta &rel_time) { + TimeTicks now = TimeTicks::Now(); + TimeTicks end = now + rel_time; + while (true) { + int64_t msec = (end - now).InMilliseconds(); + if (msec >= static_cast(INFINITE)) { + DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1); + if (result == WAIT_OBJECT_0) { + return true; + } + DCHECK(result == WAIT_TIMEOUT); + now = TimeTicks::Now(); + } else { + DWORD result = WaitForSingleObject(native_handle_, (msec < 0) ? 0 : static_cast(msec)); + if (result == WAIT_TIMEOUT) { + return false; + } + DCHECK(result == WAIT_OBJECT_0); + return true; + } + } +} + +#endif // V8_OS_MACOSX + +} // namespace base +} // namespace v8 diff --git a/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/semaphore.h b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/semaphore.h new file mode 100644 index 0000000..cff4cd4 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Backend/UserMode/UnifiedInterface/semaphore.h @@ -0,0 +1,98 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BASE_PLATFORM_SEMAPHORE_H_ +#define V8_BASE_PLATFORM_SEMAPHORE_H_ + +#include "src/base/base-export.h" +#include "src/base/lazy-instance.h" +#if V8_OS_WIN +#include "src/base/win32-headers.h" +#endif + +#if V8_OS_MACOSX +#include // NOLINT +#elif V8_OS_POSIX +#include // NOLINT +#endif + +namespace v8 { +namespace base { + +// Forward declarations. +class TimeDelta; + +// ---------------------------------------------------------------------------- +// Semaphore +// +// A semaphore object is a synchronization object that maintains a count. The +// count is decremented each time a thread completes a wait for the semaphore +// object and incremented each time a thread signals the semaphore. When the +// count reaches zero, threads waiting for the semaphore blocks until the +// count becomes non-zero. + +class V8_BASE_EXPORT Semaphore final { +public: + explicit Semaphore(int count); + ~Semaphore(); + + // Increments the semaphore counter. + void Signal(); + + // Decrements the semaphore counter if it is positive, or blocks until it + // becomes positive and then decrements the counter. + void Wait(); + + // Like Wait() but returns after rel_time time has passed. If the timeout + // happens the return value is false and the counter is unchanged. Otherwise + // the semaphore counter is decremented and true is returned. + bool WaitFor(const TimeDelta &rel_time) V8_WARN_UNUSED_RESULT; + +#if V8_OS_MACOSX + using NativeHandle = dispatch_semaphore_t; +#elif V8_OS_POSIX + using NativeHandle = sem_t; +#elif V8_OS_WIN + using NativeHandle = HANDLE; +#endif + + NativeHandle &native_handle() { + return native_handle_; + } + const NativeHandle &native_handle() const { + return native_handle_; + } + +private: + NativeHandle native_handle_; + + DISALLOW_COPY_AND_ASSIGN(Semaphore); +}; + +// POD Semaphore initialized lazily (i.e. the first time Pointer() is called). +// Usage: +// // The following semaphore starts at 0. +// static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER; +// +// void my_function() { +// // Do something with my_semaphore.Pointer(). +// } +// + +template struct CreateSemaphoreTrait { + static Semaphore *Create() { + return new Semaphore(N); + } +}; + +template struct LazySemaphore { + using typename LazyDynamicInstance, ThreadSafeInitOnceTrait>::type; +}; + +#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER + +} // namespace base +} // namespace v8 + +#endif // V8_BASE_PLATFORM_SEMAPHORE_H_ diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/InstructionRelocation.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/InstructionRelocation.h new file mode 100644 index 0000000..ebd0121 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/InstructionRelocation.h @@ -0,0 +1,5 @@ +#include "dobby_internal.h" + +void GenRelocateCode(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch); + +void GenRelocateCodeAndBranch(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated); diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/arm/InstructionRelocationARM.cc b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm/InstructionRelocationARM.cc new file mode 100644 index 0000000..9b836c7 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm/InstructionRelocationARM.cc @@ -0,0 +1,917 @@ +#include "platform_macro.h" + +#if defined(TARGET_ARCH_ARM) + +#include "dobby_internal.h" + +#include "InstructionRelocation/arm/InstructionRelocationARM.h" + +#include "core/arch/arm/registers-arm.h" +#include "core/assembler/assembler-arm.h" +#include "core/codegen/codegen-arm.h" + +using namespace zz; +using namespace zz::arm; + +typedef struct { + addr_t mapped_addr; + + bool thumb_mode; + + uint8_t *buffer; + uint8_t *buffer_cursor; + size_t buffer_size; + + vmaddr_t src_vmaddr; + vmaddr_t dst_vmaddr; + + CodeMemBlock *relocated; + CodeBuffer *relocated_buffer; + + ExecuteState start_state; + ExecuteState curr_state; + Assembler *curr_assembler; + ThumbTurboAssembler *thumb_assembler; + TurboAssembler *arm_assembler; + + tinystl::unordered_map execute_state_map; + + tinystl::unordered_map relocated_offset_map; + + tinystl::unordered_map label_map; +} relo_ctx_t; + +// --- + +addr_t relo_cur_src_vmaddr(relo_ctx_t *ctx) { + int relocated_len = ctx->buffer_cursor - ctx->buffer; + if (ctx->curr_state == zz::arm::ARMExecuteState) { + return ctx->src_vmaddr + relocated_len + ARM_PC_OFFSET; + } else { + return ctx->src_vmaddr + relocated_len + Thumb_PC_OFFSET; + } +} + +static bool is_thumb2(uint32_t insn) { + uint16_t insn1, insn2; + insn1 = insn & 0x0000ffff; + insn2 = (insn & 0xffff0000) >> 16; + // refer: Top level T32 instruction set encoding + uint32_t op0 = bits(insn1, 13, 15); + uint32_t op1 = bits(insn1, 11, 12); + + if (op0 == 0b111 && op1 != 0b00) { + return true; + } + return false; +} + +bool check_execute_state_changed(relo_ctx_t *ctx, addr_t insn_addr) { + for (auto iter = ctx->execute_state_map.begin(); iter != ctx->execute_state_map.end(); ++iter) { + addr_t execute_state_changed_pc = iter->first; + auto state = iter->second; + if (execute_state_changed_pc == insn_addr) { + return true; + } + } + return false; +} + +static inline int32_t SignExtend(unsigned x, int M, int N) { +#if 1 + char sign_bit = bit(x, M - 1); + unsigned sign_mask = 0 - sign_bit; + x |= ((sign_mask >> M) << M); +#else + x = (long)((long)x << (N - M)) >> (N - M); +#endif + return (int32_t) x; +} + +enum arm_shift_type { + arm_shift_lsl, arm_shift_lsr, arm_shift_asr, arm_shift_ror, arm_shift_rrx +}; + +uint32_t arm_shift_c(uint32_t val, uint32_t shift_type, uint32_t shift_count, uint32_t carry_in, + uint32_t *carry_out) { + if (shift_count == 0) + return val; + uint32_t r_val; + uint32_t carry = carry_in; + switch (shift_type) { + case arm_shift_lsl: + r_val = val; + r_val = r_val << shift_count; + carry = (r_val >> 32) & 0x1; + val = r_val; + break; + case arm_shift_lsr: + r_val = val; + r_val = r_val >> (shift_count - 1); + carry = r_val & 0x1; + val = (r_val >> 1); + break; + case arm_shift_asr: + r_val = val; + if (val & 0x80000000) { + r_val |= 0xFFFFFFFF00000000ULL; + } + r_val = r_val >> (shift_count - 1); + carry = r_val & 0x1; + val = (r_val >> 1); + break; + case arm_shift_ror: + val = (val >> (shift_count % 32)) | (val << (32 - (shift_count % 32))); + carry = (val >> 31); + break; + case arm_shift_rrx: + carry = val & 0x1; + val = (carry_in << 31) | (val >> 1); + break; + break; + } + return val; +} + +uint32_t arm_expand_imm_c(uint32_t imm12) { + uint32_t unrotated_value = bits(imm12, 0, 7); + return arm_shift_c(unrotated_value, arm_shift_ror, 2 * bits(imm12, 8, 11), 0, 0); +} + +uint32_t A32ExpandImm(uint32_t imm12) { + return arm_expand_imm_c(imm12); +} + +static void ARMRelocateSingleInsn(relo_ctx_t *ctx, int32_t insn) { + auto turbo_assembler_ = static_cast(ctx->curr_assembler); +#define _ turbo_assembler_-> + + bool is_insn_relocated = false; + + // top level encoding + uint32_t cond, op0, op1; + cond = bits(insn, 28, 31); + op0 = bits(insn, 25, 27); + op1 = bit(insn, 4); + // Load/Store Word, Unsigned byte (immediate, literal) + if (cond != 0b1111 && op0 == 0b010) { + uint32_t P, U, o2, W, o1, Rn, Rt, imm12; + P = bit(insn, 24); + U = bit(insn, 23); + W = bit(insn, 21); + imm12 = bits(insn, 0, 11); + Rn = bits(insn, 16, 19); + Rt = bits(insn, 12, 15); + o1 = bit(insn, 20); + o2 = bit(insn, 22); + uint32_t P_W = (P << 1) | W; + do { + // LDR (literal) + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + if (o1 == 1 && o2 == 0 && P_W != 0b01 && Rn == 0b1111) { + goto load_literal_fix_scheme; + } + if (o1 == 1 && o2 == 1 && P_W != 0b01 && Rn == 0b1111) { + goto load_literal_fix_scheme; + } + break; + load_literal_fix_scheme: + addr32_t dst_vmaddr = 0; + if (U == 0b1) + dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm12; + else + dst_vmaddr = relo_cur_src_vmaddr(ctx) - imm12; + Register regRt = Register::R(Rt); + + auto label = new RelocLabel(dst_vmaddr); + _ AppendRelocLabel(label); + + if (regRt.code() == pc.code()) { + _ Ldr(VOLATILE_REGISTER, label); + _ ldr(regRt, MemOperand(VOLATILE_REGISTER)); + } else { + _ Ldr(regRt, label); + _ ldr(regRt, MemOperand(regRt)); + } + + is_insn_relocated = true; + } while (0); + } + + // Data-processing and miscellaneous instructions + if (cond != 0b1111 && (op0 & 0b110) == 0b000) { + uint32_t op0, op1, op2, op3, op4; + op0 = bit(insn, 25); + // Data-processing immediate + if (op0 == 1) { + uint32_t op0, op1; + op0 = bits(insn, 23, 24); + op1 = bits(insn, 20, 21); + // Integer Data Processing (two register and immediate) + if ((op0 & 0b10) == 0b00) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t opc, S, Rn; + opc = bits(insn, 21, 23); + S = bit(insn, 20); + Rn = bits(insn, 16, 19); + + uint32_t dst_vmaddr = -1; + int Rd = bits(insn, 12, 15); + int imm12 = bits(insn, 0, 11); + uint32_t imm = arm_expand_imm_c(imm12); + if (opc == 0b010 && S == 0b0 && Rn == 0b1111) { // ADR - A2 variant + dst_vmaddr = relo_cur_src_vmaddr(ctx) - imm; + } else if (opc == 0b100 && S == 0b0 && Rn == 0b1111) { // ADR - A1 variant + dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + } + + if (dst_vmaddr != -1) { + Register regRd = Register::R(Rd); + RelocLabel *pseudoDataLabel = new RelocLabel(dst_vmaddr); + _ AppendRelocLabel(pseudoDataLabel); + + _ Ldr(regRd, pseudoDataLabel); + + is_insn_relocated = true; + } + } + } + } + + // Branch, branch with link, and block data transfer + if ((op0 & 0b110) == 0b100) { + uint32_t cond, op0; + cond = bits(insn, 28, 31); + op0 = bit(insn, 25); + // Branch (immediate) on page F4-4034 + if (op0 == 1) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t H = 0, imm24 = 0; + H = bit(insn, 24); + imm24 = bits(insn, 0, 23); + int32_t label = SignExtend(imm24 << 2, 2 + 24, 32); + uint32_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + label; + bool branch_link; + if (cond != 0b1111 && H == 0) { // B + branch_link = false; + } else if (cond != 0b1111 && H == 1) { // BL, BLX (immediate) - A1 on page F5-4135 + branch_link = true; + } else if (cond == 0b1111) { // BL, BLX (immediate) - A2 on page F5-4135 + branch_link = true; + cond = AL; + dst_vmaddr |= 1; + } else + UNREACHABLE(); + + if (branch_link) + _ bl((Condition) cond, 0); // goto [dst_vmaddr] + else + _ b((Condition) cond, 0); // goto [dst_vmaddr] + _ b(4); // goto [rest_flow] + // [dst_vmaddr] + _ ldr(pc, MemOperand(pc, -4)); + _ EmitAddress(dst_vmaddr); + // [rest_flow] + _ mov(r8, r8); + + is_insn_relocated = true; + } + } + + // if the insn do not needed relocate, just rewrite the origin + if (!is_insn_relocated) { + _ EmitARMInst(insn); + } +} + +// relocate thumb-1 instructions +static void Thumb1RelocateSingleInsn(relo_ctx_t *ctx, int16_t insn) { + auto turbo_assembler_ = static_cast(ctx->curr_assembler); +#define _ turbo_assembler_-> + + bool is_insn_relocated = false; + + _ AlignThumbNop(); + + uint32_t op = 0, rt = 0, rm = 0, rn = 0, rd = 0, shift = 0, cond = 0; + int32_t offset = 0; + + int32_t op0 = 0, op1 = 0; + op0 = bits(insn, 10, 15); + // Special data instructions and branch and exchange on page F3-3942 + if (op0 == 0b010001) { + op0 = bits(insn, 8, 9); + // Add, subtract, compare, move (two high registers) + if (op0 != 0b11) { + int rs = bits(insn, 3, 6); + // rs is PC register + if (rs == 15) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + thumb1_inst_t rewrite_inst = insn; + set_bits(rewrite_inst, 3, 6, VOLATILE_REGISTER.code()); + + auto label = new ThumbRelocLabelEntry(relo_cur_src_vmaddr(ctx), false); + _ AppendRelocLabel(label); + + _ T2_Ldr(VOLATILE_REGISTER, label); + _ EmitInt16(rewrite_inst); + + is_insn_relocated = true; + } + } + + // Branch and exchange + if (op0 == 0b11) { + int32_t L = bit(insn, 7); + rm = bits(insn, 3, 6); + // BX + if (L == 0b0) { + if (rm == pc.code()) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx); + auto label = new ThumbRelocLabelEntry(dst_vmaddr, true); + _ AppendRelocLabel(label); + + _ T2_Ldr(pc, label); + + ctx->execute_state_map[dst_vmaddr] = ARMExecuteState; + + is_insn_relocated = true; + } + } + // BLX + if (L == 0b1) { + if (rm == pc.code()) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx); + auto label = new ThumbRelocLabelEntry(dst_vmaddr, true); + _ AppendRelocLabel(label); + + _ t2_bl(4); + _ t2_b(4); // goto [rest flow] + _ T2_Ldr(pc, label); // goto [dst_vmaddr] + // [rest flow] + + ctx->execute_state_map[dst_vmaddr] = ARMExecuteState; + + is_insn_relocated = true; + } + } + } + } + + // LDR (literal) - T1 variant on page F5-4243 + // ldr literal + if ((insn & 0xf800) == 0x4800) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t imm8 = bits(insn, 0, 7); + uint32_t imm = imm8 << 2; + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + dst_vmaddr = ALIGN_FLOOR(dst_vmaddr, 4); + rt = bits(insn, 8, 10); + + auto label = new ThumbRelocLabelEntry(dst_vmaddr, false); + _ AppendRelocLabel(label); + + _ T2_Ldr(Register::R(rt), label); + _ t2_ldr(Register::R(rt), MemOperand(Register::R(rt), 0)); + + is_insn_relocated = true; + } + + // Add PC/SP (immediate) on page F3-3939 + // adr + if ((insn & 0xf800) == 0xa000) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + rd = bits(insn, 8, 10); + uint32_t imm8 = bits(insn, 0, 7); + int32_t imm32 = imm8 << 2; + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm32; + + auto label = new ThumbRelocLabelEntry(dst_vmaddr, false); + _ AppendRelocLabel(label); + + _ T2_Ldr(Register::R(rd), label); + + is_insn_relocated = true; + } + + // Conditional branch, and Supervisor Call on page F3-3946 + // b + if ((insn & 0xf000) == 0xd000) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint16_t cond = bits(insn, 8, 11); + // cond != 111x + if (cond >= 0b1110) { + UNREACHABLE(); + } + uint32_t imm8 = bits(insn, 0, 7); + int32_t imm = SignExtend(imm8 << 1, 8 + 1, 32); + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + dst_vmaddr |= 1; + + auto label = new ThumbRelocLabelEntry(dst_vmaddr, true); + _ AppendRelocLabel(label); + + thumb1_inst_t b_cond_insn = 0xe000; + set_bits(b_cond_insn, 8, 11, cond); + _ EmitInt16(b_cond_insn | (4 >> 1)); + _ t1_nop(); // align + _ t2_b(4); + _ T2_Ldr(pc, label); + + is_insn_relocated = true; + } + + // Miscellaneous 16-bit instructions on page F3-3943 + // CBNZ, CBZ + if ((insn & 0xf500) == 0xb100) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t imm5 = bits(insn, 3, 7); + uint32_t i = bit(insn, 9); + uint32_t imm = (i << 6) | (imm5 << 1); + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + + rn = bits(insn, 0, 2); + + auto label = new ThumbRelocLabelEntry(dst_vmaddr + 1, true); + _ AppendRelocLabel(label); + + imm5 = bits(0x4, 1, 5); + set_bits(insn, 3, 7, imm5); + i = bit(0x4, 6); + set_bit(insn, 9, i); + _ EmitInt16(insn); + _ t1_nop(); // align + _ t2_b(4); // goto [rest flow] + _ T2_Ldr(pc, label); + // [rest flow] + + is_insn_relocated = true; + } + + // F3.1 + // T32 instruction set encoding + // b + if ((insn & 0xf800) == 0xe000) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t imm11 = bits(insn, 0, 10); + int32_t imm = SignExtend(imm11 << 1, 11 + 1, 32); + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + + auto label = new ThumbRelocLabelEntry(dst_vmaddr + 1, true); + _ AppendRelocLabel(label); + + _ T2_Ldr(pc, label); + + is_insn_relocated = true; + } + + // if the insn do not needed relocate, just rewrite the origin + if (!is_insn_relocated) { +#if 0 + if (relo_cur_src_vmaddr(ctx) % Thumb2_INST_LEN) + _ t1_nop(); +#endif + _ EmitInt16(insn); + } +} + +static void Thumb2RelocateSingleInsn(relo_ctx_t *ctx, thumb1_inst_t insn1, thumb1_inst_t insn2) { + auto turbo_assembler_ = static_cast(ctx->curr_assembler); +#define _ turbo_assembler_-> + + bool is_insn_relocated = false; + + // if (turbo_assembler->pc_offset() % 4) { + // _ t1_nop(); + // } + + _ AlignThumbNop(); + + // Branches and miscellaneous control on page F3-3979 + if ((insn1 & 0xf800) == 0xf000 && (insn2 & 0x8000) == 0x8000) { + uint32_t op1 = 0, op3 = 0; + op1 = bits(insn1, 6, 9); + op3 = bits(insn2, 12, 14); + + // B - T3 variant on page F5-4118 + if (((op1 & 0b1110) != 0b1110) && ((op3 & 0b101) == 0b000)) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t S = bit(insn1, 10); + uint32_t J1 = bit(insn2, 13); + uint32_t J2 = bit(insn2, 11); + uint32_t imm6 = bits(insn1, 0, 5); + uint32_t imm11 = bits(insn2, 0, 10); + + int32_t imm = + SignExtend((S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1), + 1 + 1 + 1 + 6 + 11 + 1, 32); + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + dst_vmaddr |= 1; + + uint32_t cond = bits(insn1, 6, 9); + thumb1_inst_t b_cond_insn = 0xe000; + set_bits(b_cond_insn, 8, 11, cond); + _ EmitInt16(b_cond_insn | (4 >> 1)); + _ t1_nop(); // align + _ t2_b(8); + _ t2_ldr(pc, MemOperand(pc, 0)); + _ EmitAddress(dst_vmaddr); + + is_insn_relocated = true; + } + + // B - T4 variant on page F5-4118 + if ((op3 & 0b101) == 0b001) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t S = bit(insn1, 10); + uint32_t J1 = bit(insn2, 13); + uint32_t J2 = bit(insn2, 11); + uint32_t imm10 = bits(insn1, 0, 9); + uint32_t imm11 = bits(insn2, 0, 10); + uint32_t i1 = !(J1 ^ S); + uint32_t i2 = !(J2 ^ S); + + int32_t imm = + SignExtend((S << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1), + 1 + 1 + 1 + 10 + 11 + 1, 32); + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + dst_vmaddr |= 1; + + _ t2_ldr(pc, MemOperand(pc, 0)); + _ EmitAddress(dst_vmaddr); + + is_insn_relocated = true; + } + + // BL, BLX (immediate) - T1 variant on page F5-4135 + if ((op3 & 0b101) == 0b101) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t S = bit(insn1, 10); + uint32_t J1 = bit(insn2, 13); + uint32_t J2 = bit(insn2, 11); + uint32_t i1 = !(J1 ^ S); + uint32_t i2 = !(J2 ^ S); + uint32_t imm11 = bits(insn2, 0, 10); + uint32_t imm10 = bits(insn1, 0, 9); + int32_t imm = + SignExtend((S << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1), + 1 + 1 + 1 + 10 + 11 + 1, 32); + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + dst_vmaddr |= 1; + + _ t2_bl(4); + _ t2_b(8); + _ t2_ldr(pc, MemOperand(pc, 0)); + _ EmitAddress(dst_vmaddr); + + is_insn_relocated = true; + } + + // BL, BLX (immediate) - T2 variant on page F5-4136 + if ((op3 & 0b101) == 0b100) { + DLOG(0, "%d:relo at %p", ctx->relocated_offset_map.size(), + relo_cur_src_vmaddr(ctx)); + + uint32_t S = bit(insn1, 10); + uint32_t J1 = bit(insn2, 13); + uint32_t J2 = bit(insn2, 11); + uint32_t i1 = !(J1 ^ S); + uint32_t i2 = !(J2 ^ S); + uint32_t imm10h = bits(insn1, 0, 9); + uint32_t imm10l = bits(insn2, 1, 10); + int32_t imm = + SignExtend((S << 24) | (i1 << 23) | (i2 << 22) | (imm10h << 12) | (imm10l << 2), + 1 + 1 + 1 + 10 + 10 + 1, 32); + vmaddr_t dst_vmaddr = relo_cur_src_vmaddr(ctx); + dst_vmaddr = ALIGN_FLOOR(dst_vmaddr, 4); + dst_vmaddr+= imm; + + _ t2_bl(4); + _ t2_b(8); + _ t2_ldr(pc, MemOperand(pc, 0)); + _ EmitAddress(dst_vmaddr); + + is_insn_relocated = true; + } + } + + // Data-processing (plain binary immediate) on page F3-3983 + if ((insn1 & (0xfa10)) == 0xf200 & (insn2 & 0x8000) == 0) { + uint32_t op0 = 0, op1 = 0; + op0 = bit(insn1, 8); + op1 = bits(insn2, 5, 6); + + // Data-processing (simple immediate) + if (op0 == 0 && (op1 & 0b10) == 0b00) { + int o1 = bit(insn1, 7); + int o2 = bit(insn1, 5); + int rn = bits(insn1, 0, 3); + + // ADR + if (((o1 == 0 && o2 == 0) || (o1 == 1 && o2 == 1)) && rn == 0b1111) { + uint32_t i = bit(insn1, 10); + uint32_t imm3 = bits(insn2, 12, 14); + uint32_t imm8 = bits(insn2, 0, 7); + uint32_t rd = bits(insn2, 8, 11); + uint32_t imm = (i << 11) | (imm3 << 8) | imm8; + + vmaddr_t dst_vmaddr = 0; + if (o1 == 0 && o2 == 0) { // ADR - T3 on page F5-4098 + dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + } else if (o1 == 1 && o2 == 1) { // ADR - T2 on page F5-4097 + dst_vmaddr = relo_cur_src_vmaddr(ctx) - imm; + } else { + UNREACHABLE(); + } + + _ t2_ldr(Register::R(rd), MemOperand(pc, 4)); + _ t2_b(0); + _ EmitAddress(dst_vmaddr); + + is_insn_relocated = true; + } + } + } + + // Load/store single on page F3-3988 + // Load, unsigned (literal) on page F3-3992 + // Load, signed (literal) on page F3-3996 + // LDR literal (T2) + if ((insn1 & 0xff7f) == 0xf85f) { + uint32_t U = bit(insn1, 7); + uint32_t imm12 = bits(insn2, 0, 11); + uint16_t rt = bits(insn2, 12, 15); + + uint32_t imm = imm12; + + vmaddr_t dst_vmaddr = 0; + if (U == 1) { + dst_vmaddr = relo_cur_src_vmaddr(ctx) + imm; + } else { + dst_vmaddr = relo_cur_src_vmaddr(ctx) - imm; + } + + Register regRt = Register::R(rt); + + _ t2_ldr(regRt, MemOperand(pc, 8)); + _ t2_ldr(regRt, MemOperand(regRt, 0)); + _ t2_b(4); + _ EmitAddress(dst_vmaddr); + + is_insn_relocated = true; + } + + // if the insn not needed relocate, just rewrite the origin + if (!is_insn_relocated) { +#if 0 + if (relo_cur_src_vmaddr(ctx) % Thumb2_INST_LEN) + _ t1_nop(); +#endif + _ EmitInt16(insn1); + _ EmitInt16(insn2); + } +} + +void gen_arm_relocate_code(relo_ctx_t *ctx) { + +#undef _ +#define _ turbo_assembler_-> + auto turbo_assembler_ = static_cast(ctx->curr_assembler); +#define _ turbo_assembler_-> + + auto relocated_buffer = turbo_assembler_->GetCodeBuffer(); + + DLOG(0, "[arm] ARM relocate %d start >>>>>", ctx->buffer_size); + + while (ctx->buffer_cursor < ctx->buffer + ctx->buffer_size) { + uint32_t orig_off = ctx->buffer_cursor - ctx->buffer; + uint32_t relocated_off = relocated_buffer->GetBufferSize(); + ctx->relocated_offset_map[orig_off] = relocated_off; + + arm_inst_t insn = *(arm_inst_t *) ctx->buffer_cursor; + + int last_relo_offset = turbo_assembler_->GetCodeBuffer()->GetBufferSize(); + + ARMRelocateSingleInsn(ctx, insn); + DLOG(0, "[arm] Relocate arm insn: 0x%x", insn); + + // move to next instruction + ctx->buffer_cursor += ARM_INST_LEN; + + // execute state changed + addr32_t next_insn_addr = relo_cur_src_vmaddr(ctx) - ARM_PC_OFFSET; + if (check_execute_state_changed(ctx, next_insn_addr)) { + break; + } + } + + bool is_relocate_interrupted = ctx->buffer_cursor < ctx->buffer + ctx->buffer_size; + if (is_relocate_interrupted) { + turbo_assembler_->SetExecuteState(ThumbExecuteState); + } +} + +void gen_thumb_relocate_code(relo_ctx_t *ctx) { + int relocated_insn_count = 0; + + auto turbo_assembler_ = static_cast(ctx->curr_assembler); +#define _ turbo_assembler_-> + + auto relocated_buffer = turbo_assembler_->GetCodeBuffer(); + + DLOG(0, "[arm] Thumb relocate %d start >>>>>", ctx->buffer_size); + + while (ctx->buffer_cursor < ctx->buffer + ctx->buffer_size) { + uint32_t orig_off = ctx->buffer_cursor - ctx->buffer; + uint32_t relocated_off = relocated_buffer->GetBufferSize(); + ctx->relocated_offset_map[orig_off] = relocated_off; + + // align nop + _ t1_nop(); + + thumb2_inst_t insn = *(thumb2_inst_t *) ctx->buffer_cursor; + + int last_relo_offset = relocated_buffer->GetBufferSize(); + if (is_thumb2(insn)) { + Thumb2RelocateSingleInsn(ctx, (uint16_t) insn, (uint16_t) (insn >> 16)); + DLOG(0, "[arm] Relocate thumb2 insn: 0x%x", insn); + } else { + Thumb1RelocateSingleInsn(ctx, (uint16_t) insn); + DLOG(0, "[arm] Relocate thumb1 insn: 0x%x", (uint16_t) insn); + } + + // Move to next instruction + if (is_thumb2(insn)) { + ctx->buffer_cursor += Thumb2_INST_LEN; + } else { + ctx->buffer_cursor += Thumb1_INST_LEN; + } + + // execute state changed + addr32_t next_insn_addr = relo_cur_src_vmaddr(ctx) - Thumb_PC_OFFSET; + if (check_execute_state_changed(ctx, next_insn_addr)) { + break; + } + } + + // .thumb1 bx pc + // .thumb1 mov r8, r8 + // .arm ldr pc, [pc, #-4] + + bool is_relocate_interrupted = ctx->buffer_cursor < ctx->buffer + ctx->buffer_size; + if (is_relocate_interrupted) { + turbo_assembler_->SetExecuteState(ARMExecuteState); + } +} + +void GenRelocateCode(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch) { + relo_ctx_t ctx; + + if ((addr_t) buffer % 2) { + ctx.start_state = ThumbExecuteState; + ctx.curr_state = ThumbExecuteState; + // remove thumb address flag + buffer = (void *) ((addr_t) buffer - 1); + } else { + ctx.start_state = ARMExecuteState; + ctx.curr_state = ARMExecuteState; + } + + ctx.buffer = ctx.buffer_cursor = (uint8_t *) buffer; + ctx.buffer_size = origin->size; + + ctx.src_vmaddr = (vmaddr_t) origin->addr; + ctx.dst_vmaddr = 0; + + auto *relocated_buffer = new CodeBuffer(); + ctx.relocated_buffer = relocated_buffer; + + ThumbTurboAssembler thumb_turbo_assembler_(0, ctx.relocated_buffer); +#define thumb_ thumb_turbo_assembler_. + TurboAssembler arm_turbo_assembler_(0, ctx.relocated_buffer); +#define arm_ arm_turbo_assembler_. + + if (ctx.start_state == ThumbExecuteState) + ctx.curr_assembler = &thumb_turbo_assembler_; + else + ctx.curr_assembler = &arm_turbo_assembler_; + + relocate_remain: + if (ctx.curr_state == ThumbExecuteState) { + ctx.curr_assembler = &thumb_turbo_assembler_; + gen_thumb_relocate_code(&ctx); + if (thumb_turbo_assembler_.GetExecuteState() == ARMExecuteState) { + // translate interrupt as execute state changed + bool is_translate_interrupted = ctx.buffer_cursor < ctx.buffer + ctx.buffer_size; + if (is_translate_interrupted) { + // add nop to align ARM + if (thumb_turbo_assembler_.pc_offset() % 4) + thumb_turbo_assembler_.t1_nop(); + goto relocate_remain; + } + } + } else { + ctx.curr_assembler = &arm_turbo_assembler_; + gen_arm_relocate_code(&ctx); + if (arm_turbo_assembler_.GetExecuteState() == ThumbExecuteState) { + bool is_translate_interrupted = ctx.buffer_cursor < ctx.buffer + ctx.buffer_size; + // translate interrupt as execute state changed + if (is_translate_interrupted) { + goto relocate_remain; + } + } + } + + // update origin + int new_origin_len = (addr_t)ctx.buffer_cursor - (addr_t)ctx.buffer; + origin->reset(origin->addr, new_origin_len); + + // TODO: if last insn is unlink branch, skip + if (branch) { + if (ctx.curr_state == ThumbExecuteState) { + // branch to the rest of instructions + thumb_ AlignThumbNop(); + thumb_ t2_ldr(pc, MemOperand(pc, 0)); + // get the real branch address + thumb_ EmitAddress(origin->addr + origin->size + THUMB_ADDRESS_FLAG); + } else { + // branch to the rest of instructions + CodeGen codegen(&arm_turbo_assembler_); + // get the real branch address + codegen.LiteralLdrBranch(origin->addr + origin->size); + } + } + + // fixup the insn branch into trampoline(has been modified) + arm_turbo_assembler_.RelocLabelFixup(&ctx.relocated_offset_map); + thumb_turbo_assembler_.RelocLabelFixup(&ctx.relocated_offset_map); + + // realize all the pseudo data label + thumb_turbo_assembler_.RelocBind(); + arm_turbo_assembler_.RelocBind(); + + // generate executable code + { + // assembler without specific memory address + auto relocated_mem = MemoryAllocator::SharedAllocator()->allocateExecMemory( + relocated_buffer->GetBufferSize()); + if (relocated_mem == nullptr) + return; + + thumb_turbo_assembler_.SetRealizedAddress((void *) relocated_mem); + arm_turbo_assembler_.SetRealizedAddress((void *) relocated_mem); + + AssemblyCode *code = NULL; + code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(ctx.curr_assembler); + relocated->reset(code->addr, code->size); + } + + // thumb + if (ctx.start_state == ThumbExecuteState) { + // add thumb address flag + relocated->reset(relocated->addr + THUMB_ADDRESS_FLAG, relocated->size); + } + + // clean + { + thumb_turbo_assembler_.ClearCodeBuffer(); + arm_turbo_assembler_.ClearCodeBuffer(); + + delete relocated_buffer; + } +} + +void GenRelocateCodeAndBranch(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated) { + GenRelocateCode(buffer, origin, relocated, true); +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/arm/InstructionRelocationARM.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm/InstructionRelocationARM.h new file mode 100644 index 0000000..e33413d --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm/InstructionRelocationARM.h @@ -0,0 +1,300 @@ +#pragma once +#include "dobby_internal.h" + +#include "core/arch/arm/constants-arm.h" +#include "core/assembler/assembler-arm.h" + +namespace zz { +namespace arm { + +// thumb1/thumb2 pseudo label type, only support Thumb1-Ldr | Thumb2-Ldr +enum ref_label_type_t { kThumb1Ldr, kThumb2LiteralLdr }; + +// custom thumb pseudo label for thumb/thumb2 +class ThumbPseudoLabel : public AssemblerPseudoLabel { +public: + // fix the instruction which not link to the label yet. + void link_confused_instructions(CodeBuffer *buffer) { + CodeBuffer *_buffer; + if (buffer) + _buffer = buffer; + + for (auto &ref_label_inst : ref_label_insts_) { + // instruction offset to label + thumb2_inst_t insn = _buffer->LoadThumb2Inst(ref_label_inst.offset_); + thumb1_inst_t insn1 = _buffer->LoadThumb1Inst(ref_label_inst.offset_); + thumb1_inst_t insn2 = _buffer->LoadThumb1Inst(ref_label_inst.offset_ + sizeof(thumb1_inst_t)); + + switch (ref_label_inst.type_) { + case kThumb1Ldr: { + UNREACHABLE(); + } break; + case kThumb2LiteralLdr: { + int64_t pc = ref_label_inst.offset_ + Thumb_PC_OFFSET; + assert(pc % 4 == 0); + int32_t imm12 = relocated_pos() - pc; + + if (imm12 > 0) { + set_bit(insn1, 7, 1); + } else { + set_bit(insn1, 7, 0); + imm12 = -imm12; + } + set_bits(insn2, 0, 11, imm12); + _buffer->RewriteThumb1Inst(ref_label_inst.offset_, insn1); + _buffer->RewriteThumb1Inst(ref_label_inst.offset_ + Thumb1_INST_LEN, insn2); + + DLOG(0, "[thumb label link] insn offset %d link offset %d", ref_label_inst.offset_, imm12); + } break; + default: + UNREACHABLE(); + break; + } + } + } +}; + +class ThumbRelocLabelEntry : public ThumbPseudoLabel, public RelocLabel { +public: + template + ThumbRelocLabelEntry(T value, bool is_pc_register) + : RelocLabel(value), ThumbPseudoLabel(), is_pc_register_(is_pc_register) { + } + + bool is_pc_register() { + return is_pc_register_; + } + +private: + bool is_pc_register_; +}; + +// --- + +class ThumbAssembler : public Assembler { +public: + ThumbAssembler(void *address) : Assembler(address) { + this->SetExecuteState(ThumbExecuteState); + } + + ThumbAssembler(void *address, CodeBuffer *buffer) : Assembler(address, buffer) { + this->SetExecuteState(ThumbExecuteState); + } + + void EmitInt16(int16_t val) { + buffer_->Emit16(val); + } + + void Emit2Int16(int16_t val1, int16_t val2) { + EmitInt16(val1); + EmitInt16(val2); + } + + void EmitAddress(uint32_t value) { + buffer_->Emit32(value); + } + + // ===== + void t1_nop() { + EmitInt16(0xbf00); + } + void t1_b(int32_t imm) { + ASSERT(CheckSignLength(imm, 12)); + ASSERT(CheckAlign(imm, 2)); + + int32_t imm11 = bits(imm >> 1, 0, 10); + EmitInt16(0xe000 | imm11); + } + + // ===== + void t2_b(uint32_t imm) { + EmitThumb2Branch(AL, imm, false); + } + void t2_bl(uint32_t imm) { + EmitThumb2Branch(AL, imm, true); + } + void t2_blx(uint32_t imm) { + UNIMPLEMENTED(); + } + + // ===== + void t2_ldr(Register dst, const MemOperand &src) { + // WARNNING: literal ldr, base = ALIGN(pc, 4) + EmitThumb2LoadStore(true, dst, src); + } + +private: + void EmitThumb2LoadLiteral(Register rt, const MemOperand x) { + bool add = true; + uint32_t U, imm12; + int32_t offset = x.offset(); + +#if 0 + // literal ldr, base = ALIGN(pc, 4) + if (rt.Is(pc)) { + // TODO: convert to `GetRealizedAddress()` ??? + addr_t curr_pc = pc_offset() + (addr_t)GetRealizedAddress(); + if (curr_pc % 4) { + t1_nop(); + } + } +#endif + + if (offset > 0) { + U = B7; + imm12 = offset; + } else { + U = 0; + imm12 = -offset; + } + EmitInt16(0xf85f | U); + EmitInt16(0x0 | (rt.code() << 12) | imm12); + } + void EmitThumb2LoadStore(bool load, Register rt, const MemOperand x) { + if (x.rn().Is(pc)) { + EmitThumb2LoadLiteral(rt, x); + return; + } + + bool index, add, wback; + if (x.IsRegisterOffset() && x.offset() >= 0) { + index = true, add = true, wback = false; + uint32_t imm12 = x.offset(); + EmitInt16(0xf8d0 | (x.rn().code() << 0)); + EmitInt16(0x0 | (rt.code() << 12) | imm12); + } else { + // use bit accelerate + uint32_t P = 0, W = 0, U = 0; + uint32_t imm8 = x.offset() > 0 ? x.offset() : -x.offset(); + U = x.offset() > 0 ? 0 : B9; + if (x.IsPostIndex()) { + P = 0, W = B8; + } else if (x.IsPreIndex()) { + P = B10, W = B8; + } + index = (P == B10); + add = (U == B9); + wback = (W == B8); + EmitInt16(0xf850 | (x.rn().code() << 0)); + EmitInt16(0x0800 | (rt.code() << 12) | P | U | W | imm8); + } + } + + void EmitThumb2Branch(Condition cond, int32_t imm, bool link) { + uint32_t operand = imm >> 1; + ASSERT(CheckSignLength(operand, 25)); + ASSERT(CheckAlign(operand, 2)); + + uint32_t signbit = (imm >> 31) & 0x1; + uint32_t i1 = (operand >> 22) & 0x1; + uint32_t i2 = (operand >> 21) & 0x1; + uint32_t imm10 = (operand >> 11) & 0x03ff; + uint32_t imm11 = operand & 0x07ff; + uint32_t j1 = (!(i1 ^ signbit)); + uint32_t j2 = (!(i2 ^ signbit)); + + if (cond != AL) { + UNIMPLEMENTED(); + } + + EmitInt16(0xf000 | LeftShift(signbit, 1, 10) | LeftShift(imm10, 10, 0)); + if (link) { + // Not use LeftShift(1, 1, 14), and use B14 for accelerate + EmitInt16(0x9000 | LeftShift(j1, 1, 13) | (LeftShift(j2, 1, 11)) | LeftShift(imm11, 11, 0) | B14); + } else { + EmitInt16(0x9000 | LeftShift(j1, 1, 13) | (LeftShift(j2, 1, 11)) | LeftShift(imm11, 11, 0)); + } + } +}; + +// --- + +class ThumbTurboAssembler : public ThumbAssembler { +public: + ThumbTurboAssembler(void *address) : ThumbAssembler(address) { + } + + ThumbTurboAssembler(void *address, CodeBuffer *buffer) : ThumbAssembler(address, buffer) { + } + + ~ThumbTurboAssembler() { + } + + void T1_Ldr(Register rt, ThumbPseudoLabel *label) { + UNREACHABLE(); + +// t1_ldr: rt can't be PC register +// === +#if 0 + if (label->is_bound()) { + const int64_t dest = label->pos() - buffer_.Size(); + ldr(rt, MemOperand(pc, dest)); + } else { + // record this ldr, and fix later. + label->link_to(buffer_.Size(), ThumbPseudoLabel::kThumb1Ldr); + ldr(rt, MemOperand(pc, 0)); + } +#endif + } + + void T2_Ldr(Register rt, ThumbPseudoLabel *label) { + if (label->relocated_pos()) { + int offset = label->relocated_pos() - buffer_->GetBufferSize(); + t2_ldr(rt, MemOperand(pc, offset)); + } else { + // record this ldr, and fix later. + label->link_to(kThumb2LiteralLdr, 0, buffer_->GetBufferSize()); + t2_ldr(rt, MemOperand(pc, 0)); + } + } + + void AlignThumbNop() { + addr32_t pc = this->GetCodeBuffer()->GetBufferSize() + (uintptr_t)GetRealizedAddress(); + if (pc % Thumb2_INST_LEN) { + t1_nop(); + } else { + } + } + + // --- + + void PseudoBind(ThumbPseudoLabel *label) { + const addr_t bound_pc = buffer_->GetBufferSize(); + label->bind_to(bound_pc); + // If some instructions have been wrote, before the label bound, we need link these `confused` instructions + if (label->has_confused_instructions()) { + label->link_confused_instructions(GetCodeBuffer()); + } + } + + void RelocBind() { + for (auto *data_label : data_labels_) { + PseudoBind(data_label); + reinterpret_cast(buffer_)->EmitBuffer(data_label->data_, data_label->data_size_); + } + } + + void AppendRelocLabel(ThumbRelocLabelEntry *label) { + data_labels_.push_back(label); + } + + void RelocLabelFixup(tinystl::unordered_map *relocated_offset_map) { + for (auto *data_label : data_labels_) { + auto val = data_label->data(); + auto iter = relocated_offset_map->find(val); + if (iter != relocated_offset_map->end()) { + data_label->fixup_data(iter->second); + } + } + } + +private: + std::vector data_labels_; +}; + +#if 0 +void GenRelocateCodeAndBranch(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated); +#endif + +} // namespace arm +} // namespace zz diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/InstructionRelocationARM64.cc b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/InstructionRelocationARM64.cc new file mode 100644 index 0000000..49d447c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/InstructionRelocationARM64.cc @@ -0,0 +1,366 @@ +#include "platform_macro.h" + +#if defined(TARGET_ARCH_ARM64) + +#include "InstructionRelocation/arm64/InstructionRelocationARM64.h" + +#include "dobby_internal.h" + +#include "core/arch/arm64/registers-arm64.h" +#include "core/assembler/assembler-arm64.h" +#include "core/codegen/codegen-arm64.h" + +#include "inst_constants.h" +#include "inst_decode_encode_kit.h" + +using namespace zz::arm64; + +#if defined(DOBBY_DEBUG) +#define debug_nop() _ nop() +#else +#define debug_nop() +#endif + +#define arm64_trunc_page(x) ((x) & (~(0x1000 - 1))) +#define arm64_round_page(x) trunc_page((x) + (0x1000 - 1)) + +typedef struct { + addr_t mapped_addr; + + uint8_t *buffer; + uint8_t *buffer_cursor; + size_t buffer_size; + + vmaddr_t src_vmaddr; + vmaddr_t dst_vmaddr; + + CodeMemBlock *origin; + CodeMemBlock *relocated; + + tinystl::unordered_map relocated_offset_map; + + tinystl::unordered_map label_map; + +} relo_ctx_t; + +// --- + +addr_t relo_cur_src_vmaddr(relo_ctx_t *ctx) { + return ctx->src_vmaddr + (ctx->buffer_cursor - ctx->buffer); +} + +addr_t relo_cur_dst_vmaddr(relo_ctx_t *ctx, TurboAssembler *assembler) { + return ctx->dst_vmaddr + assembler->GetCodeBuffer()->GetBufferSize(); +} + +addr_t relo_src_offset_to_vmaddr(relo_ctx_t *ctx, off_t offset) { + return ctx->src_vmaddr + offset; +} + +addr_t relo_dst_offset_to_vmaddr(relo_ctx_t *ctx, off_t offset) { + return ctx->dst_vmaddr + offset; +} + +// --- + +#if 0 +bool has_relo_label_at(relo_ctx_t *ctx, vmaddr_t addr) { + if (ctx->label_map.count(addr)) { + return true; + } + return false; +} + +AssemblerPseudoLabel *relo_label_create_or_get(relo_ctx_t *ctx, vmaddr_t addr) { + if (!ctx->label_map.count(addr)) { + auto *label = new AssemblerPseudoLabel(addr); + ctx->label_map[addr] = label; + } + return ctx->label_map[addr]; +} + +int64_t relo_label_link_offset(relo_ctx_t *ctx, pcrel_type_t pcrel_type, int64_t offset) { + auto is_offset_undefined = [ctx](int64_t offset) -> bool { + if (ctx->buffer_cursor + offset < ctx->buffer || ctx->buffer_cursor + offset > ctx->buffer + ctx->buffer_size) { + return true; + } + return false; + }; + + auto is_offset_uninitialized = [ctx](int64_t offset) -> bool { + if (ctx->buffer_cursor + offset > ctx->buffer && ctx->buffer_cursor + offset < ctx->buffer + ctx->buffer_size) { + if (!ctx->relocated_offset_map.count(ctx->buffer_cursor + offset - ctx->buffer_cursor)) + return true; + } + return false; + }; + + addr_t label_vmaddr = relo_cur_src_vmaddr(ctx) + offset; + if (pcrel_type == RELO_ARM64_RELOC_PAGE21) { + label_vmaddr = arm64_trunc_page(label_vmaddr); + } + + auto *label = relo_label_create_or_get(ctx, label_vmaddr); + if (is_offset_undefined(offset)) { // pc relative target is beyond our scope + label->link_to(AssemblerPseudoLabel::kLabelImm19, relo_cur_src_vmaddr(ctx), (addr_t)ctx->buffer_cursor - ctx->mapped_addr); + return 0; + } else if (is_offset_uninitialized(offset)) { // pc relative target is in our control, but not handle yet + label->link_to(AssemblerPseudoLabel::kLabelImm19, relo_cur_src_vmaddr(ctx), (addr_t)ctx->buffer_cursor - ctx->mapped_addr); + return 0; + } else { // pc relative target is already handled + off_t off = ctx->buffer_cursor + offset - ctx->buffer; + off_t relocated_off = label->relocated_pos(); + int64_t new_offset = relo_dst_offset_to_vmaddr(ctx, relocated_off) - relo_src_offset_to_vmaddr(ctx, off); + return new_offset; + } +} +#endif + +// --- + +static inline bool inst_is_b_bl(uint32_t instr) { + return (instr & UnconditionalBranchFixedMask) == UnconditionalBranchFixed; +} + +static inline bool inst_is_ldr_literal(uint32_t instr) { + return ((instr & LoadRegLiteralFixedMask) == LoadRegLiteralFixed); +} + +static inline bool inst_is_adr(uint32_t instr) { + return (instr & PCRelAddressingFixedMask) == PCRelAddressingFixed && (instr & PCRelAddressingMask) == ADR; +} + +static inline bool inst_is_adrp(uint32_t instr) { + return (instr & PCRelAddressingFixedMask) == PCRelAddressingFixed && (instr & PCRelAddressingMask) == ADRP; +} + +static inline bool inst_is_b_cond(uint32_t instr) { + return (instr & ConditionalBranchFixedMask) == ConditionalBranchFixed; +} + +static inline bool inst_is_compare_b(uint32_t instr) { + return (instr & CompareBranchFixedMask) == CompareBranchFixed; +} + +static inline bool inst_is_test_b(uint32_t instr) { + return (instr & TestBranchFixedMask) == TestBranchFixed; +} + +// --- + +int relo_relocate(relo_ctx_t *ctx, bool branch) { + int relocated_insn_count = 0; + + TurboAssembler turbo_assembler_(0); +#define _ turbo_assembler_. + + auto relocated_buffer = turbo_assembler_.GetCodeBuffer(); + + while (ctx->buffer_cursor < ctx->buffer + ctx->buffer_size) { + uint32_t orig_off = ctx->buffer_cursor - ctx->buffer; + uint32_t relocated_off = relocated_buffer->GetBufferSize(); + ctx->relocated_offset_map[orig_off] = relocated_off; + +#if 0 + vmaddr_t inst_vmaddr = 0; + inst_vmaddr = relo_cur_src_vmaddr(ctx); + if (has_relo_label_at(ctx, inst_vmaddr)) { + auto *label = relo_label_create_or_get(ctx, inst_vmaddr); + label->bind_to(inst_vmaddr); + } +#endif + + arm64_inst_t inst = *(arm64_inst_t *)ctx->buffer_cursor; + if (inst_is_b_bl(inst)) { + DLOG(0, "%d:relo at %p", relocated_insn_count++, relo_cur_src_vmaddr(ctx)); + + int64_t offset = decode_imm26_offset(inst); + addr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + offset; + + RelocLabel *dst_label = new RelocLabel(dst_vmaddr); + _ AppendRelocLabel(dst_label); + + { + _ Ldr(TMP_REG_0, dst_label); + if ((inst & UnconditionalBranchMask) == BL) { + _ blr(TMP_REG_0); + } else { + _ br(TMP_REG_0); + } + } + + } else if (inst_is_ldr_literal(inst)) { + DLOG(0, "%d:relo at %p", relocated_insn_count++, relo_cur_src_vmaddr(ctx)); + + int64_t offset = decode_imm19_offset(inst); + addr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + offset; + + int rt = decode_rt(inst); + char opc = bits(inst, 30, 31); + + { + _ Mov(TMP_REG_0, dst_vmaddr); + if (opc == 0b00) + _ ldr(W(rt), MemOperand(TMP_REG_0, 0)); + else if (opc == 0b01) + _ ldr(X(rt), MemOperand(TMP_REG_0, 0)); + else { + UNIMPLEMENTED(); + } + } + } else if (inst_is_adr(inst)) { + DLOG(0, "%d:relo at %p", relocated_insn_count++, relo_cur_src_vmaddr(ctx)); + + int64_t offset = decode_immhi_immlo_offset(inst); + addr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + offset; + + int rd = decode_rd(inst); + + { + _ Mov(X(rd), dst_vmaddr); + ; + } + } else if (inst_is_adrp(inst)) { + DLOG(0, "%d:relo at %p", relocated_insn_count++, relo_cur_src_vmaddr(ctx)); + + int64_t offset = decode_immhi_immlo_zero12_offset(inst); + addr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + offset; + dst_vmaddr = arm64_trunc_page(dst_vmaddr); + + int rd = decode_rd(inst); + + { + _ Mov(X(rd), dst_vmaddr); + ; + } + } else if (inst_is_b_cond(inst)) { + DLOG(0, "%d:relo at %p", relocated_insn_count++, relo_cur_src_vmaddr(ctx)); + + int64_t offset = decode_imm19_offset(inst); + addr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + offset; + + arm64_inst_t branch_instr = inst; + { + char cond = bits(inst, 0, 3); + cond = cond ^ 1; + set_bits(branch_instr, 0, 3, cond); + + int64_t offset = 4 * 3; + uint32_t imm19 = offset >> 2; + set_bits(branch_instr, 5, 23, imm19); + } + + RelocLabel *dst_label = new RelocLabel(dst_vmaddr); + _ AppendRelocLabel(dst_label); + + { + _ Emit(branch_instr); + { + _ Ldr(TMP_REG_0, dst_label); + _ br(TMP_REG_0); + } + } + } else if (inst_is_compare_b(inst)) { + DLOG(0, "%d:relo at %p", relocated_insn_count++, relo_cur_src_vmaddr(ctx)); + + int64_t offset = decode_imm19_offset(inst); + addr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + offset; + + arm64_inst_t branch_instr = inst; + { + char op = bit(inst, 24); + op = op ^ 1; + set_bit(branch_instr, 24, op); + + int64_t offset = 4 * 3; + uint32_t imm19 = offset >> 2; + set_bits(branch_instr, 5, 23, imm19); + } + + RelocLabel *dst_label = new RelocLabel(dst_vmaddr); + _ AppendRelocLabel(dst_label); + + { + _ Emit(branch_instr); + { + _ Ldr(TMP_REG_0, dst_label); + _ br(TMP_REG_0); + } + } + } else if (inst_is_test_b(inst)) { + DLOG(0, "%d:relo at %p", relocated_insn_count++, relo_cur_src_vmaddr(ctx)); + + int64_t offset = decode_imm14_offset(inst); + addr_t dst_vmaddr = relo_cur_src_vmaddr(ctx) + offset; + + arm64_inst_t branch_instr = inst; + { + char op = bit(inst, 24); + op = op ^ 1; + set_bit(branch_instr, 24, op); + + int64_t offset = 4 * 3; + uint32_t imm14 = offset >> 2; + set_bits(branch_instr, 5, 18, imm14); + } + + RelocLabel *dst_label = new RelocLabel(dst_vmaddr); + _ AppendRelocLabel(dst_label); + + { + _ Emit(branch_instr); + { + _ Ldr(TMP_REG_0, dst_label); + _ br(TMP_REG_0); + } + } + } else { + _ Emit(inst); + } + + ctx->buffer_cursor += sizeof(arm64_inst_t); + } +#undef _ + + // update origin + int new_origin_len = (addr_t)ctx->buffer_cursor - (addr_t)ctx->buffer; + ctx->origin->reset(ctx->origin->addr, new_origin_len); + + // TODO: if last instr is unlink branch, ignore it + if (branch) { + CodeGen codegen(&turbo_assembler_); + codegen.LiteralLdrBranch(ctx->origin->addr + ctx->origin->size); + } + + // Bind all labels + turbo_assembler_.RelocBind(); + + // Generate executable code + { + auto code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + ctx->relocated = code; + } + return 0; +} + +void GenRelocateCode(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch) { + relo_ctx_t ctx = {0}; + + ctx.buffer = ctx.buffer_cursor = (uint8_t *)buffer; + ctx.buffer_size = origin->size; + + ctx.src_vmaddr = (vmaddr_t)origin->addr; + ctx.dst_vmaddr = (vmaddr_t)relocated->addr; + + ctx.origin = origin; + + relo_relocate(&ctx, branch); + + relocated->reset(ctx.relocated->addr, ctx.relocated->size); +} + +void GenRelocateCodeAndBranch(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated) { + GenRelocateCode(buffer, origin, relocated, true); +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/InstructionRelocationARM64.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/InstructionRelocationARM64.h new file mode 100644 index 0000000..c42bfd7 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/InstructionRelocationARM64.h @@ -0,0 +1,13 @@ +#pragma once + +#include "dobby_internal.h" + +#include "core/arch/arm64/constants-arm64.h" + +#if 0 +namespace zz { +namespace arm64 { +void GenRelocateCodeAndBranch(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated); +} // namespace arm64 +} // namespace zz +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/inst_constants.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/inst_constants.h new file mode 100644 index 0000000..228a952 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/inst_constants.h @@ -0,0 +1,49 @@ +#pragma once + +#if 0 +enum LoadRegLiteralOp { + LoadRegLiteralFixed = 0x18000000, + LoadRegLiteralFixedMask = 0x3B000000, + LoadRegLiteralMask = 0xFF000000, +}; + +// PC relative addressing. +enum PCRelAddressingOp { + PCRelAddressingFixed = 0x10000000, + PCRelAddressingFixedMask = 0x1F000000, + PCRelAddressingMask = 0x9F000000, + ADR = PCRelAddressingFixed | 0x00000000, + ADRP = PCRelAddressingFixed | 0x80000000 +}; + +// Unconditional branch. +enum UnconditionalBranchOp { + UnconditionalBranchFixed = 0x14000000, + UnconditionalBranchFixedMask = 0x7C000000, + UnconditionalBranchMask = 0xFC000000, + + B = UnconditionalBranchFixed | 0x00000000, + BL = UnconditionalBranchFixed | 0x80000000 +}; +#endif + +// Compare and branch. +enum CompareBranchOp { + CompareBranchFixed = 0x34000000, + CompareBranchFixedMask = 0x7E000000, + CompareBranchMask = 0xFF000000, +}; + +// Conditional branch. +enum ConditionalBranchOp { + ConditionalBranchFixed = 0x54000000, + ConditionalBranchFixedMask = 0xFE000000, + ConditionalBranchMask = 0xFF000010, +}; + +// Test and branch. +enum TestBranchOp { + TestBranchFixed = 0x36000000, + TestBranchFixedMask = 0x7E000000, + TestBranchMask = 0x7F000000, +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/inst_decode_encode_kit.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/inst_decode_encode_kit.h new file mode 100644 index 0000000..306618e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/arm64/inst_decode_encode_kit.h @@ -0,0 +1,110 @@ +#pragma once + +#include "common_header.h" + +static inline int64_t SignExtend(unsigned long x, int M, int N) { +#if 1 + char sign_bit = bit(x, M - 1); + unsigned long sign_mask = 0 - sign_bit; + x |= ((sign_mask >> M) << M); +#else + x = (long)((long)x << (N - M)) >> (N - M); +#endif + return (int64_t )x; +} + +static inline int64_t decode_imm14_offset(uint32_t instr) { + int64_t offset; + { + int64_t imm14 = bits(instr, 5, 18); + offset = (imm14 << 2); + } + offset = SignExtend(offset, 2 + 14, 64); + return offset; +} +static inline uint32_t encode_imm14_offset(uint32_t instr, int64_t offset) { + uint32_t imm14 = bits((offset >> 2), 0, 13); + set_bits(instr, 5, 18, imm14); + return instr; +} + +static inline int64_t decode_imm19_offset(uint32_t instr) { + int64_t offset; + { + int64_t imm19 = bits(instr, 5, 23); + offset = (imm19 << 2); + } + offset = SignExtend(offset, 2 + 19, 64); + return offset; +} + +static inline uint32_t encode_imm19_offset(uint32_t instr, int64_t offset) { + uint32_t imm19 = bits((offset >> 2), 0, 18); + set_bits(instr, 5, 23, imm19); + return instr; +} + +static inline int64_t decode_imm26_offset(uint32_t instr) { + int64_t offset; + { + int64_t imm26 = bits(instr, 0, 25); + offset = (imm26 << 2); + } + offset = SignExtend(offset, 2 + 26, 64); + return offset; +} +static inline uint32_t encode_imm26_offset(uint32_t instr, int64_t offset) { + uint32_t imm26 = bits((offset >> 2), 0, 25); + set_bits(instr, 0, 25, imm26); + return instr; +} + +static inline int64_t decode_immhi_immlo_offset(uint32_t instr) { + typedef uint32_t instr_t; + struct { + instr_t Rd : 5; // Destination register + instr_t immhi : 19; // 19-bit upper immediate + instr_t dummy_0 : 5; // Must be 10000 == 0x10 + instr_t immlo : 2; // 2-bit lower immediate + instr_t op : 1; // 0 = ADR, 1 = ADRP + } instr_decode; + + *(instr_t *)&instr_decode = instr; + + int64_t imm = instr_decode.immlo + (instr_decode.immhi << 2); + imm = SignExtend(imm, 2 + 19, 64); + return imm; +} +static inline uint32_t encode_immhi_immlo_offset(uint32_t instr, int64_t offset) { + struct { + uint32_t Rd : 5; // Destination register + uint32_t immhi : 19; // 19-bit upper immediate + uint32_t dummy_0 : 5; // Must be 10000 == 0x10 + uint32_t immlo : 2; // 2-bit lower immediate + uint32_t op : 1; // 0 = ADR, 1 = ADRP + } instr_decode; + + *(uint32_t *)&instr_decode = instr; + instr_decode.immlo = bits(offset, 0, 2); + instr_decode.immhi = bits(offset, 2, 2 + 19); + + return *(uint32_t *)&instr_decode; +} + +static inline int64_t decode_immhi_immlo_zero12_offset(uint32_t instr) { + int64_t imm = decode_immhi_immlo_offset(instr); + imm = imm << 12; + return imm; +} +static inline uint32_t encode_immhi_immlo_zero12_offset(uint32_t instr, int64_t offset) { + offset = (offset >> 12); + return encode_immhi_immlo_offset(instr, offset); +} + +static inline int decode_rt(uint32_t instr) { + return bits(instr, 0, 4); +} + +static inline int decode_rd(uint32_t instr) { + return bits(instr, 0, 4); +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x64/InstructionRelocationX64.cc b/app/src/main/cpp/Dobby/source/InstructionRelocation/x64/InstructionRelocationX64.cc new file mode 100644 index 0000000..eb052c9 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x64/InstructionRelocationX64.cc @@ -0,0 +1,78 @@ +#include "platform_macro.h" + +#if defined(TARGET_ARCH_X64) + +#include "dobby_internal.h" + +#include "InstructionRelocation/x64/InstructionRelocationX64.h" +#include "InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h" + +#include "core/arch/x64/registers-x64.h" +#include "core/assembler/assembler-x64.h" +#include "core/codegen/codegen-x64.h" + +using namespace zz::x64; + +int GenRelocateCodeFixed(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch) { + TurboAssembler turbo_assembler_(0); + // Set fixed executable code chunk address + turbo_assembler_.SetRealizedAddress((void *)relocated->addr); +#define _ turbo_assembler_. +#define __ turbo_assembler_.GetCodeBuffer()-> + + auto curr_orig_ip = (addr64_t)origin->addr; + auto curr_relo_ip = (addr64_t)relocated->addr; + + uint8_t *buffer_cursor = (uint8_t *)buffer; + + int predefined_relocate_size = origin->size; + + while ((buffer_cursor < ((uint8_t *)buffer + predefined_relocate_size))) { + x86_insn_decode_t insn = {0}; + memset(&insn, 0, sizeof(insn)); + GenRelocateSingleX86Insn(curr_orig_ip, curr_relo_ip, buffer_cursor, turbo_assembler_.GetCodeBuffer(), insn, 64); + + // go next + curr_orig_ip += insn.length; + buffer_cursor += insn.length; + curr_relo_ip = (addr64_t)relocated->addr + turbo_assembler_.ip_offset(); + } + + // jmp to the origin rest instructions + if (branch) { + CodeGen codegen(&turbo_assembler_); + // TODO: 6 == jmp [RIP + disp32] instruction size + addr64_t stub_addr = curr_relo_ip + 6; + codegen.JmpNearIndirect(stub_addr); + turbo_assembler_.GetCodeBuffer()->Emit64(curr_orig_ip); + } + + // update origin + int new_origin_len = curr_orig_ip - (addr_t)origin->addr; + origin->reset(origin->addr, new_origin_len); + + int relo_len = turbo_assembler_.GetCodeBuffer()->GetBufferSize(); + if (relo_len > relocated->size) { + DLOG(0, "pre-alloc code chunk not enough"); + return RT_FAILED; + } + + // generate executable code + { + auto code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + relocated->reset(code->addr, code->size); + delete code; + } + + return RT_SUCCESS; +} + +void GenRelocateCodeAndBranch(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated) { + GenRelocateCode(buffer, origin, relocated, true); +} + +void GenRelocateCode(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch) { + GenRelocateCodeX86Shared(buffer, origin, relocated, branch); +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x64/InstructionRelocationX64.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/x64/InstructionRelocationX64.h new file mode 100644 index 0000000..04e6afa --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x64/InstructionRelocationX64.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common_header.h" + +#include "core/arch/x64/constants-x64.h" + +#include "MemoryAllocator/AssemblyCodeBuilder.h" + +#include "InstructionRelocation/x86/InstructionRelocationX86Shared.h" diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86.cc b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86.cc new file mode 100644 index 0000000..df1f62b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86.cc @@ -0,0 +1,79 @@ +#include "platform_macro.h" + +#if defined(TARGET_ARCH_IA32) + +#include "dobby_internal.h" + +#include "InstructionRelocation/x86/InstructionRelocationX86.h" +#include "InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h" + +#include "core/arch/x86/registers-x86.h" +#include "core/assembler/assembler-ia32.h" +#include "core/codegen/codegen-ia32.h" + +using namespace zz::x86; + +int GenRelocateCodeFixed(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch) { + TurboAssembler turbo_assembler_(0); + // Set fixed executable code chunk address + turbo_assembler_.SetRealizedAddress((void *)relocated->addr); +#define _ turbo_assembler_. +#define __ turbo_assembler_.GetCodeBuffer()-> + + auto curr_orig_ip = (addr32_t)origin->addr; + auto curr_relo_ip = (addr32_t)relocated->addr; + + uint8_t *buffer_cursor = (uint8_t *)buffer; + + x86_options_t conf = {0}; + conf.mode = 32; + + int predefined_relocate_size = origin->size; + + while ((buffer_cursor < ((uint8_t *)buffer + predefined_relocate_size))) { + x86_insn_decode_t insn = {0}; + memset(&insn, 0, sizeof(insn)); + GenRelocateSingleX86Insn(curr_orig_ip, curr_relo_ip, buffer_cursor, turbo_assembler_.GetCodeBuffer(), insn, 64); + + // go next + curr_orig_ip += insn.length; + buffer_cursor += insn.length; + curr_relo_ip = (addr32_t)relocated->addr + turbo_assembler_.ip_offset(); + } + + // jmp to the origin rest instructions + if (branch) { + CodeGen codegen(&turbo_assembler_); + addr32_t stub_addr = curr_relo_ip + 6; + codegen.JmpNear(curr_orig_ip); + } + + // update origin + int new_origin_len = curr_orig_ip - (addr_t)origin->addr; + origin->reset(origin->addr, new_origin_len); + + int relo_len = turbo_assembler_.GetCodeBuffer()->GetBufferSize(); + if (relo_len > relocated->size) { + DLOG(0, "pre-alloc code chunk not enough"); + return RT_FAILED; + } + + // generate executable code + { + auto code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + relocated->reset(code->addr, code->size); + delete code; + } + + return RT_SUCCESS; +} + +void GenRelocateCodeAndBranch(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated) { + GenRelocateCode(buffer, origin, relocated, true); +} + +void GenRelocateCode(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch) { + GenRelocateCodeX86Shared(buffer, origin, relocated, branch); +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86.h new file mode 100644 index 0000000..df04f0d --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common_header.h" + +#include "core/arch/x86/constants-x86.h" + +#include "MemoryAllocator/AssemblyCodeBuilder.h" + +#include "InstructionRelocation/x86/InstructionRelocationX86Shared.h" diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86Shared.cc b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86Shared.cc new file mode 100644 index 0000000..8b573fd --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86Shared.cc @@ -0,0 +1,196 @@ +#include "platform_macro.h" + +#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) + +#include "dobby_internal.h" + +#include "InstructionRelocation/x86/InstructionRelocationX86.h" +#include "InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h" +#include "MemoryAllocator/NearMemoryAllocator.h" + +using namespace zz::x86; + +// x64 jmp absolute address +void codegen_x64_jmp_absolute_addr(CodeBufferBase *buffer, addr_t target) { + // jmp *(rip) + buffer->Emit8(0xFF); + buffer->Emit8(0x25); // ModR/M: 00 100 101 + buffer->Emit32(0x00); + // .long target + buffer->Emit64(target); +} + +int GenRelocateSingleX86Insn(addr_t curr_orig_ip, addr_t curr_relo_ip, uint8_t *buffer_cursor, + CodeBufferBase *code_buffer, x86_insn_decode_t &insn, int8_t mode) { +#define __ code_buffer-> + + int relocated_insn_len = -1; + + x86_options_t conf = {0}; + conf.mode = mode; + + // decode x86 insn + x86_insn_decode(&insn, (uint8_t *)buffer_cursor, &conf); + + // x86 ip register == next instruction + curr_orig_ip = curr_orig_ip + insn.length; + + int last_relo_offset = code_buffer->GetBufferSize(); + if (insn.primary_opcode >= 0x70 && insn.primary_opcode <= 0x7F) { // jc rel8 + DLOG(0, "[x86 relo] %p: jc rel8", buffer_cursor); + + int8_t offset = insn.immediate; + + uint8_t opcode = 0x80 | (insn.primary_opcode & 0x0f); + +#if defined(TARGET_ARCH_IA32) + curr_relo_ip = curr_relo_ip + 6; + int32_t new_offset = (int32_t)(curr_orig_ip + offset - curr_relo_ip); + + __ Emit8(0x0F); + __ Emit8(opcode); + __ Emit32(new_offset); +#else + curr_relo_ip = curr_relo_ip + 2 + 2 + 6 + 8; + uint64_t orig_insn_ref_addr = curr_orig_ip + offset; + + // jcc + __ Emit8(opcode); + __ Emit8(2); + + // jmp + __ Emit8(0xEB); + __ Emit8(6 + 8); + + // jmp abs addr + codegen_x64_jmp_absolute_addr(code_buffer, orig_insn_ref_addr); +#endif + + } else if (mode == 64 && (insn.flags & X86_INSN_DECODE_FLAG_IP_RELATIVE) && + (insn.operands[1].mem.base == RIP)) { // RIP + DLOG(0, "[x86 relo] %p: rip", buffer_cursor); + + curr_relo_ip = curr_relo_ip + 6 + 8; + + addr_t rip_insn_seq_addr = 0; + { + int32_t orig_disp = insn.operands[1].mem.disp; + addr_t orig_rip_ref_addr = curr_orig_ip + orig_disp; + + uint32_t jmp_near_range = (uint32_t)2 * 1024 * 1024 * 1024; + auto rip_insn_seq = (addr_t)NearMemoryAllocator::SharedAllocator()->allocateNearExecMemory( + insn.length + 6 + 8, orig_rip_ref_addr, jmp_near_range); + + rip_insn_seq_addr = rip_insn_seq; + + auto rip_insn_seq_buffer = CodeBufferBase(); +#define ___ rip_insn_seq_buffer. + + auto rip_insn_req_ip = rip_insn_seq; + rip_insn_req_ip = rip_insn_req_ip + insn.length; // next insn addr + int32_t new_disp = (int32_t)(orig_rip_ref_addr - rip_insn_req_ip); + + // keep orig insn opcode + ___ EmitBuffer(buffer_cursor, insn.displacement_offset); + ___ Emit32(new_disp); + // keep orig insn immediate + if (insn.immediate_offset) { + ___ EmitBuffer((buffer_cursor + insn.immediate_offset), insn.length - insn.immediate_offset); + } + + // jmp *(rip) => back to relo process + codegen_x64_jmp_absolute_addr(&rip_insn_seq_buffer, curr_relo_ip); + + DobbyCodePatch((void *)rip_insn_seq, rip_insn_seq_buffer.GetBuffer(), rip_insn_seq_buffer.GetBufferSize()); + } + + // jmp *(rip) => jmp to [rip insn seq] + __ Emit8(0xFF); + __ Emit8(0x25); // ModR/M: 00 100 101 + __ Emit32(0); + __ Emit64(rip_insn_seq_addr); + } else if (insn.primary_opcode == 0xEB) { // jmp rel8 + DLOG(0, "[x86 relo] %p: jmp rel8", buffer_cursor); + + int8_t offset = insn.immediate; + +#if defined(TARGET_ARCH_IA32) + curr_relo_ip = curr_relo_ip + 5; + int32_t new_offset = (int32_t)(curr_orig_ip + offset - curr_relo_ip); + + __ Emit8(0xE9); + __ Emit32(new_offset); +#else + curr_relo_ip = curr_relo_ip + 6 + 8; + uint64_t orig_insn_ref_addr = curr_orig_ip + offset; + + // jmp *(rip) + codegen_x64_jmp_absolute_addr(code_buffer, orig_insn_ref_addr); +#endif + } else if (insn.primary_opcode == 0xE8 || insn.primary_opcode == 0xE9) { // call or jmp rel32 + DLOG(0, "[x86 relo] %p:jmp or call rel32", buffer_cursor); + + int32_t offset = insn.immediate; + + assert(insn.immediate_offset == 1); + +#if defined(TARGET_ARCH_IA32) + curr_relo_ip = curr_relo_ip + 5; + int32_t new_offset = (int32_t)(curr_orig_ip + offset - curr_relo_ip); + + __ EmitBuffer(buffer_cursor, insn.immediate_offset); + __ Emit32(new_offset); +#else + curr_relo_ip = curr_relo_ip + 6 + 8; + uint64_t orig_insn_ref_addr = curr_orig_ip + offset; + + // jmp *(rip) + __ Emit8(0xFF); + if (insn.primary_opcode == 0xE8) + __ Emit8(0x15); // ModR/M: 00 010 101 + else + __ Emit8(0x25); // ModR/M: 00 100 101 + __ Emit32(0); + __ Emit64(orig_insn_ref_addr); +#endif + } else if (insn.primary_opcode >= 0xE0 && insn.primary_opcode <= 0xE2) { // LOOPNZ/LOOPZ/LOOP/JECXZ + // LOOP/LOOPcc + UNIMPLEMENTED(); + } else if (insn.primary_opcode == 0xE3) { + // JCXZ JCEXZ JCRXZ + UNIMPLEMENTED(); + } else { + __ EmitBuffer(buffer_cursor, insn.length); + } + + // insn -> relocated insn + { + int relo_offset = code_buffer->GetBufferSize(); + int relo_len = relo_offset - last_relo_offset; + DLOG(0, "insn -> relocated insn: %d -> %d", insn.length, relo_len); + } + return relocated_insn_len; +} + +void GenRelocateCodeX86Shared(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch) { + int expected_relocated_mem_size = 32; +x86_try_again: + if (!relocated->addr) { + auto relocated_mem = MemoryAllocator::SharedAllocator()->allocateExecMemory(expected_relocated_mem_size); + if (relocated_mem == nullptr) { + return; + } + relocated->reset((addr_t)relocated_mem, expected_relocated_mem_size); + } + + int ret = GenRelocateCodeFixed(buffer, origin, relocated, branch); + if (ret != RT_SUCCESS) { + const int step_size = 16; + expected_relocated_mem_size += step_size; + relocated->reset(0, 0); + + goto x86_try_again; + } +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86Shared.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86Shared.h new file mode 100644 index 0000000..b4bb8f5 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86Shared.h @@ -0,0 +1,14 @@ +#pragma once + +#include "common_header.h" + +#include "MemoryAllocator/AssemblyCodeBuilder.h" + +#include "x86_insn_decode/x86_insn_decode.h" + +int GenRelocateCodeFixed(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch); + +void GenRelocateCodeX86Shared(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch); + +int GenRelocateSingleX86Insn(addr_t curr_orig_ip, addr_t curr_relo_ip, uint8_t *buffer_cursor, + CodeBufferBase *code_buffer, x86_insn_decode_t &insn, int8_t mode); \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/Ia32Disassembler.cc b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/Ia32Disassembler.cc new file mode 100644 index 0000000..e9774d1 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/Ia32Disassembler.cc @@ -0,0 +1,388 @@ +#include +#include + +#include "logging/logging.h" + +enum SegmentPrefix { + kCs = 0x2e, + kSs = 0x36, + kDs = 0x3e, + kEs = 0x26, + kFs = 0x64, + kGs = 0x65, +}; + +bool supports_rex_ = false; + +void DecodeInstruction(uint8_t *instr) { + bool have_prefixes = true; + uint8_t prefix[4] = {0, 0, 0, 0}; + + // decode legacy prefix + do { + switch (*instr) { + // Group 1 - lock and repeat prefixes: + case 0xF0: + case 0xF2: + case 0xF3: + prefix[0] = *instr; + break; + // Group 2 - segment override prefixes: + case kCs: + case kSs: + case kDs: + case kEs: + case kFs: + case kGs: + prefix[1] = *instr; + break; + // Group 3 - operand size override: + case 0x66: + prefix[2] = *instr; + break; + // Group 4 - address size override: + case 0x67: + prefix[3] = *instr; + break; + default: + have_prefixes = false; + break; + } + if (have_prefixes) { + instr++; + } + } while (have_prefixes); + + // x64 rex + uint8_t rex = (supports_rex_ && (*instr >= 0x40) && (*instr <= 0x4F)) ? *instr : 0; + if (rex != 0) { + instr++; + } + + bool has_modrm = false; + bool reg_is_opcode = false; + + size_t immediate_bytes = 0; + +#define OpEn_MR \ + do { \ + has_modrm = true; \ + } while (0); \ + break; + +#define OpEn_RM \ + do { \ + has_modrm = true; \ + } while (0); \ + break; + +#define OpEn_I(immediate_size) \ + do { \ + immediate_bytes = immediate_size; \ + } while (0); \ + break; + +#define OpEn_RMI(immediate_size) \ + do { \ + immediate_bytes = immediate_size; \ + } while (0); \ + break; + +#define OpEn_O \ + do { \ + reg_is_opcode = true; \ + } while (0); \ + break; + +#define OpEn_D \ + do { \ + reg_is_opcode = true; \ + } while (0); \ + break; + +#define OpEn_ZO \ + do { \ + reg_is_opcode = true; \ + } while (0); \ + break; + +#define Op_Prefix \ + do { \ + reg_is_opcode = true; \ + } while (0); \ + break; + +#define UnImplOpcode \ + do { \ + DLOG(0, "opcode unreachable"); \ + } while (0); \ + break; + + typedef enum { + MR, + } OpEnTy; + + // decode opcode + switch (*instr) { + case 0x00: + OpEn_MR; + case 0x01: + OpEn_MR; + case 0x02: + OpEn_RM; + case 0x03: + OpEn_RM; + case 0x04: + OpEn_I(8); + case 0x05: + OpEn_I(16 | 32); + + case 0x06: + case 0x07: + UnImplOpcode; + + case 0x08: + OpEn_MR; + case 0x09: + OpEn_MR; + case 0x0a: + OpEn_RM; + case 0x0b: + OpEn_RM; + case 0x0c: + OpEn_I(8); + case 0x0d: + OpEn_I(16 | 32); + + case 0x0e: + case 0x0f: + UnImplOpcode; + + case 0x10: + OpEn_MR; + case 0x11: + OpEn_MR; + case 0x12: + OpEn_RM; + case 0x13: + OpEn_RM; + case 0x14: + OpEn_I(8); + case 0x15: + OpEn_I(16 | 32); + + case 0x16: + case 0x17: + UnImplOpcode; + + case 0x18: + OpEn_MR; + case 0x19: + OpEn_MR; + case 0x1a: + OpEn_RM; + case 0x1b: + OpEn_RM; + case 0x1c: + OpEn_I(8); + case 0x1d: + OpEn_I(16 | 32); + + case 0x1e: + case 0x1f: + UnImplOpcode; + + case 0x20: + OpEn_MR; + case 0x21: + OpEn_MR; + case 0x22: + OpEn_RM; + case 0x23: + OpEn_RM; + case 0x24: + OpEn_I(8); + case 0x25: + OpEn_I(16 | 32); + + case 0x26: + case 0x27: + UnImplOpcode; + + case 0x28: + OpEn_MR; + case 0x29: + OpEn_MR; + case 0x2a: + OpEn_RM; + case 0x2b: + OpEn_RM; + case 0x2c: + OpEn_I(8); + case 0x2d: + OpEn_I(16 | 32); + + case 0x2e: + case 0x2f: + UnImplOpcode; + + case 0x30: + OpEn_MR; + case 0x31: + OpEn_MR; + case 0x32: + OpEn_RM; + case 0x33: + OpEn_RM; + case 0x34: + OpEn_I(8); + case 0x35: + OpEn_I(16 | 32); + + case 0x36: + case 0x37: + UnImplOpcode; + + case 0x38: + OpEn_MR; + case 0x39: + OpEn_MR; + case 0x3a: + OpEn_RM; + case 0x3b: + OpEn_RM; + case 0x3c: + OpEn_I(8); + case 0x3d: + OpEn_I(16 | 32); + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + UnImplOpcode; + + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + OpEn_O; + + case 0x60: + case 0x61: + case 0x62: + UnImplOpcode; + + case 0x63: + if ((rex & REX_W) != 0) { + OpEn_RM; + }; + break; + + case 0x64: + case 0x65: + case 0x66: + case 0x67: + Op_Prefix; + + case 0x68: + OpEn_I(16 | 32); + + case 0x69: + OpEn_RMI(16 | 32); + + case 0x6a: + OpEn_I(8); + + case 0x6b: + OpEn_RMI(8); + + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + OpEn_D; + + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + UnImplOpcode; + + case 0x86: + case 0x87: + OpEn_RM; + + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + OpEn_RM; + + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + UnImplOpcode; + + case 0x9d: + OpEn_ZO; + + case 0x0f: + DecodeExtendedOpcode + } +} + +void DecodeExtendedOpcode(uint8_t *instr) { +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/X86OpcodoDecodeTable.cc b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/X86OpcodoDecodeTable.cc new file mode 100644 index 0000000..84bfad7 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/X86OpcodoDecodeTable.cc @@ -0,0 +1,604 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) + +#include "./X86OpcodoDecodeTable.h" + +// clang-format on + +#define _xUnknownOpHanlder -1, -1, OpSz_0, ImmSz_0, _UnknownOpHanlder +void _UnknownOpHanlder(InstrMnemonic *instr, addr_t p) { + // printf("Unknown Operand\n"); + return; +} + +#define _xInvalidOpHanlder -1, -1, OpSz_0, ImmSz_0, _InValidOpHanlder +void _InValidOpHanlder(InstrMnemonic *instr, addr_t p) { + // printf("Invalid Operand\n"); + return; +} + +inline void _ContinueDispatch(InstrMnemonic *instr, addr_t p) { + OpcodeDecodeItem *item = &OpcodeDecodeTable[*(unsigned char *)p]; + item->DecodeHandler(instr, p); +} + +// ===== Decode LegacyPrefix and REXPrefix ===== + +// clang-format off +#define _xDecodePrefix_0F 1, OpEn_NONE, OpSz_0, ImmSz_0, _DecodeLegacyPrefix +#define _xDecodePrefix_66 1, OpEn_NONE, OpSz_0, ImmSz_0, _DecodePrefix_66 +#define _xDecodePrefix_67 1, OpEn_NONE, OpSz_0, ImmSz_0, _DecodeLegacyPrefix +#define _xDecodeREXPrefix 1, OpEn_NONE, OpSz_0, ImmSz_0, _DecodeREXPrefix +#define _xDecodePrefix 1, OpEn_NONE, OpSz_0, ImmSz_0, _DecodeLegacyPrefix +#define _xDecodeSegPrefix 1, OpEn_NONE, OpSz_0, ImmSz_0, _DecodeLegacyPrefix +// clang-format on + +void _DecodeREXPrefix(InstrMnemonic *instr, addr_t p) { + instr->instr.REX = *(byte_t *)p; + instr->len++; + instr->OperandSz = OpSz_64; + + _ContinueDispatch(instr, p + 1); // continue decode +} + +void _DecodeLegacyPrefix(InstrMnemonic *instr, addr_t p) { + instr->instr.prefix = *(byte_t *)p; + instr->len++; + + _ContinueDispatch(instr, p + 1); // continue decode +} + +void _DecodePrefix_66(InstrMnemonic *instr, addr_t p) { + instr->OperandSz = OpSz_16; + _DecodeLegacyPrefix(instr, p); +} + +// ===== Decode Opcode ===== + +static void _DecodeOp(InstrMnemonic *instr, addr_t p) { + instr->instr.opcode1 = *(byte_t *)p; + instr->len++; +} + +static void _DecodeOpExtraOp(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); +} + +static void _DecodeOpWithReg(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); +} + +#define _xDecodeOpEn_ZO 1, OpEn_ZO, OpSz_0, ImmSz_0, _DecodeOpEn_ZO +void _DecodeOpEn_ZO(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); +} + +#define _xDecodeOpEn_O 1, OpEn_O, OpSz_0, ImmSz_0, _DecodeOpEn_O +void _DecodeOpEn_O(InstrMnemonic *instr, addr_t p) { + _DecodeOpWithReg(instr, p); +} + +// ===== Decode Operand ===== + +// ===== Decode ModRM Operand ===== + +#define REX_W(byte) ((byte & 0b00001000) >> 3) +#define REX_R(byte) ((byte & 0b00000100) >> 2) +#define REX_X(byte) ((byte & 0b00000010) >> 1) +#define REX_B(byte) ((byte & 0b00000001) >> 0) + +#define ModRM_Mod(byte) ((byte & 0b11000000) >> 6) +#define ModRM_RegOpcode(byte) ((byte & 0b00111000) >> 3) +#define ModRM_RM(byte) (byte & 0b00000111) + +#define SIB_Scale(sib) ((sib & 0b11000000) >> 6) +#define SIB_Index(sib) ((sib & 0b00111000) >> 3) +#define SIB_Base(sib) ((sib & 0b00000111) >> 0) + +#define REX_SIB_Base(rex, sib) ((REX_B(rex) << 3) | SIB_Base(sib)) + +void _DecodeDisplacement8(InstrMnemonic *instr, addr_t p) { + *(byte_t *)&instr->instr.Displacement = *(byte_t *)p; + instr->len += 1; +} + +void _DecodeDisplacement32(InstrMnemonic *instr, addr_t p) { + instr->instr.DisplacementOffset = instr->len; + *(dword *)&instr->instr.Displacement = *(byte_t *)p; + instr->len += 4; +} + +void _DecodeSIB(InstrMnemonic *instr, addr_t p) { + instr->instr.SIB = *(byte_t *)p; + instr->len++; +} + +void _DecodeModRM(InstrMnemonic *instr, addr_t p) { + int init_len = instr->len; + + instr->instr.ModRM = *(byte_t *)p; + instr->len++; + +#if defined(_M_X64) || defined(__x86_64__) + if (ModRM_Mod(instr->instr.ModRM) == 0b00 && ModRM_RM(instr->instr.ModRM) == 0b101) { + // RIP-Relative Addressing + instr->flag = instr->flag | kIPRelativeAddress; + _DecodeDisplacement32(instr, p + (instr->len - init_len)); + return; + } +#endif + + // Addressing Forms with the SIB Byte + if (ModRM_Mod(instr->instr.ModRM) != 0b11 && ModRM_RM(instr->instr.ModRM) == 0b100) { + _DecodeSIB(instr, p + (instr->len - init_len)); + } + + // [REG] + if (ModRM_Mod(instr->instr.ModRM) == 0b00) { + if (ModRM_RM(instr->instr.ModRM) == 0b101) { + _DecodeDisplacement32(instr, p + (instr->len - init_len)); + return; + } + } + + // [REG+disp8} + if (ModRM_Mod(instr->instr.ModRM) == 0b01) { + _DecodeDisplacement8(instr, p + (instr->len - init_len)); + return; + } + + // [REG+disp32} + if (ModRM_Mod(instr->instr.ModRM) == 0b10) { + _DecodeDisplacement32(instr, p + (instr->len - init_len)); + return; + } + + // REG + if (ModRM_Mod(instr->instr.ModRM) == 0b11) { + } +} + +void _DecodeOpEn_M(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + _DecodeModRM(instr, p + 1); +} + +void _DecodeOpEn_RM(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + _DecodeModRM(instr, p + 1); +} + +void _DecodeOpEn_MR(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + _DecodeModRM(instr, p + 1); +} + +void _DecodeOpEn_M1(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + _DecodeModRM(instr, p + 1); +} + +void _DecodeOpEn_MC(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + _DecodeModRM(instr, p + 1); +} + +// ===== Decode Immediate Operand ===== + +void _DecodeImmedite(InstrMnemonic *instr, addr_t p, int sz) { + + instr->instr.ImmediateOffset = instr->len; + + OpcodeDecodeItem *item = &OpcodeDecodeTable[instr->instr.opcode1]; + if (sz == ImmSz_0) { + sz = item->ImmediteSz; + if (sz == (ImmSz_16 | ImmSz_32)) { + if (instr->instr.prefix == 0x66) { + sz = ImmSz_16; + } else { + sz = ImmSz_32; // Default Immedite Size + } + } + } + + if (sz == ImmSz_8) { + *(byte_t *)&instr->instr.Immediate = *(byte_t *)p; + instr->len += 1; + } else if (sz == ImmSz_16) { + *(word *)&instr->instr.Immediate = *(dword *)p; + instr->len += 2; + } else if (sz == ImmSz_32) { + *(dword *)&instr->instr.Immediate = *(dword *)p; + instr->len += 4; + } +} + +void _DecodeOpEn_I(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + _DecodeImmedite(instr, p + 1, instr->ImmediteSz); +} + +void _DecodeOpEn_OI(InstrMnemonic *instr, addr_t p) { + _DecodeOpWithReg(instr, p); + _DecodeImmedite(instr, p + 1, instr->ImmediteSz); +} + +void _DecodeOpEn_D(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + _DecodeImmedite(instr, p + 1, instr->ImmediteSz); +} + +// ===== Decode ModRM Immediate Operand ===== + +void _DecodeOpEn_RMI(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + _DecodeModRM(instr, p + 1); + _DecodeImmedite(instr, p + 2, instr->ImmediteSz); +} + +void _DecodeOpEn_MI(InstrMnemonic *instr, addr_t p) { + _DecodeOpExtraOp(instr, p); + _DecodeModRM(instr, p + 1); + _DecodeImmedite(instr, p + 2, instr->ImmediteSz); +} + +// ===== Decode Specific Opcode ===== + +#define _xDecodeOpC8 1, 0, OpSz_0, ImmSz_0, _DecodeOpC8 +void _DecodeOpC8(InstrMnemonic *instr, addr_t p) { + _DecodeOp(instr, p); + + instr->len = instr->len + 2 + 1; +} + +// http://ref.x86asm.net/coder.html#x04 +OpcodeDecodeItem OpcodeDecodeTable[257] = { + + {0x00, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x01, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x02, 2, OpEn_RM, OpSz_8, ImmSz_0, _DecodeOpEn_RM}, + {0x03, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x04, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x05, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, +#if defined(_M_X64) || defined(__x86_64__) + {0x06, _xInvalidOpHanlder}, + {0x07, _xInvalidOpHanlder}, +#else + {0x06, _xDecodeOpEn_ZO}, + {0x07, _xDecodeOpEn_ZO}, +#endif + {0x08, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x09, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x0A, 2, OpEn_RM, OpSz_8, ImmSz_0, _DecodeOpEn_RM}, + {0x0B, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x0C, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x0D, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, +#if defined(_M_X64) || defined(__x86_64__) + {0x0E, _xInvalidOpHanlder}, +#else + {0x0E, _xDecodeOpEn_ZO}, +#endif + {0x0F, _xDecodePrefix_0F}, + {0x10, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x11, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x12, 2, OpEn_RM, OpSz_8, ImmSz_0, _DecodeOpEn_RM}, + {0x13, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x14, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x15, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, +#if defined(_M_X64) || defined(__x86_64__) + {0x16, _xInvalidOpHanlder}, + {0x17, _xInvalidOpHanlder}, +#else + {0x16, _xDecodeOpEn_ZO}, + {0x17, _xDecodeOpEn_ZO}, +#endif + {0x18, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x19, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x1A, 2, OpEn_RM, OpSz_8, ImmSz_0, _DecodeOpEn_RM}, + {0x1B, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x1C, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x1D, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, +#if defined(_M_X64) || defined(__x86_64__) + {0x1E, _xInvalidOpHanlder}, + {0x1F, _xInvalidOpHanlder}, +#else + {0x1E, _xDecodeOpEn_ZO}, + {0x1F, _xDecodeOpEn_ZO}, +#endif + {0x20, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x21, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x22, 2, OpEn_RM, OpSz_8, ImmSz_0, _DecodeOpEn_RM}, + {0x23, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x24, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x25, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, + {0x26, _xDecodeSegPrefix}, +#if defined(_M_X64) || defined(__x86_64__) + {0x27, _xInvalidOpHanlder}, +#else + {0x27, _xDecodeOpEn_ZO}, +#endif + {0x28, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x29, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x2A, 2, OpEn_RM, OpSz_8, ImmSz_0, _DecodeOpEn_RM}, + {0x2B, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x2C, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x2D, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, + {0x2E, _xDecodeSegPrefix}, +#if defined(_M_X64) || defined(__x86_64__) + {0x2F, _xInvalidOpHanlder}, +#else + {0x2F, _xDecodeOpEn_ZO}, +#endif + {0x30, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x31, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x32, 2, OpEn_RM, OpSz_8, ImmSz_0, _DecodeOpEn_RM}, + {0x33, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x34, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x35, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, + {0x36, _xDecodeSegPrefix}, +#if defined(_M_X64) || defined(__x86_64__) + {0x37, _xInvalidOpHanlder}, +#else + {0x37, _xDecodeOpEn_ZO}, +#endif + {0x38, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x39, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x3A, 2, OpEn_RM, OpSz_8, ImmSz_0, _DecodeOpEn_RM}, + {0x3B, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x3C, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x3D, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, + {0x3E, _xDecodeSegPrefix}, +#if defined(_M_X64) || defined(__x86_64__) + {0x3F, _xInvalidOpHanlder}, +#else + {0x3F, _xDecodeOpEn_ZO}, +#endif +#if defined(_M_X64) || defined(__x86_64__) // For REX Prefix + {0x40, _xDecodeREXPrefix}, + {0x41, _xDecodeREXPrefix}, + {0x42, _xDecodeREXPrefix}, + {0x43, _xDecodeREXPrefix}, + {0x44, _xDecodeREXPrefix}, + {0x45, _xDecodeREXPrefix}, + {0x46, _xDecodeREXPrefix}, + {0x47, _xDecodeREXPrefix}, + {0x48, _xDecodeREXPrefix}, + {0x49, _xDecodeREXPrefix}, + {0x4A, _xDecodeREXPrefix}, + {0x4B, _xDecodeREXPrefix}, + {0x4C, _xDecodeREXPrefix}, + {0x4D, _xDecodeREXPrefix}, + {0x4E, _xDecodeREXPrefix}, + {0x4F, _xDecodeREXPrefix}, +#else + {0x40, _xDecodeOpEn_O}, + {0x41, _xDecodeOpEn_O}, + {0x42, _xDecodeOpEn_O}, + {0x43, _xDecodeOpEn_O}, + {0x44, _xDecodeOpEn_O}, + {0x45, _xDecodeOpEn_O}, + {0x46, _xDecodeOpEn_O}, + {0x47, _xDecodeOpEn_O}, + {0x48, _xDecodeOpEn_O}, + {0x49, _xDecodeOpEn_O}, + {0x4A, _xDecodeOpEn_O}, + {0x4B, _xDecodeOpEn_O}, + {0x4C, _xDecodeOpEn_O}, + {0x4D, _xDecodeOpEn_O}, + {0x4E, _xDecodeOpEn_O}, + {0x4F, _xDecodeOpEn_O}, +#endif + {0x50, _xDecodeOpEn_O}, + {0x51, _xDecodeOpEn_O}, + {0x52, _xDecodeOpEn_O}, + {0x53, _xDecodeOpEn_O}, + {0x54, _xDecodeOpEn_O}, + {0x55, _xDecodeOpEn_O}, + {0x56, _xDecodeOpEn_O}, + {0x57, _xDecodeOpEn_O}, + {0x58, _xDecodeOpEn_O}, + {0x59, _xDecodeOpEn_O}, + {0x5A, _xDecodeOpEn_O}, + {0x5B, _xDecodeOpEn_O}, + {0x5C, _xDecodeOpEn_O}, + {0x5D, _xDecodeOpEn_O}, + {0x5E, _xDecodeOpEn_O}, + {0x5F, _xDecodeOpEn_O}, +#if defined(_M_X64) || defined(__x86_64__) + {0x60, _xInvalidOpHanlder}, + {0x61, _xInvalidOpHanlder}, + {0x62, _xInvalidOpHanlder}, +#else + {0x60, _xDecodeOpEn_ZO}, + {0x61, _xDecodeOpEn_ZO}, + {0x62, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, +#endif + {0x63, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x64, _xDecodeSegPrefix}, + {0x65, _xDecodeSegPrefix}, + {0x66, _xDecodePrefix_66}, + {0x67, _xDecodePrefix_67}, + {0x68, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, + {0x69, 2, OpEn_RMI, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_RMI}, + {0x6A, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0x6B, 1, OpEn_RMI, OpSz_16 | OpSz_32, ImmSz_8, _DecodeOpEn_RMI}, + {0x6C, _xDecodeOpEn_ZO}, + {0x6D, _xDecodeOpEn_ZO}, + {0x6E, _xDecodeOpEn_ZO}, + {0x6F, _xDecodeOpEn_ZO}, + {0x70, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x71, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x72, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x73, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x74, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x75, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x76, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x77, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x78, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x79, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x7A, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x7B, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x7C, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x7D, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x7E, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x7F, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0x80, 2, OpEn_MI, OpSz_8, ImmSz_8, _DecodeOpEn_MI}, + {0x81, 2, OpEn_MI, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_MI}, +#if defined(_M_X64) || defined(__x86_64__) + {0x82, _xInvalidOpHanlder}, +#else + {0x82, _xUnknownOpHanlder}, +#endif + {0x83, 2, OpEn_MI, OpSz_16 | OpSz_32, ImmSz_8, _DecodeOpEn_MI}, + {0x84, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x85, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x86, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x87, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x88, 2, OpEn_MR, OpSz_8, ImmSz_0, _DecodeOpEn_MR}, + {0x89, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x8A, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x8B, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x8C, 2, OpEn_MR, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MR}, + {0x8D, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x8E, 2, OpEn_RM, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_RM}, + {0x8F, 2, OpEn_M, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_M}, + {0x90, _xDecodeOpEn_ZO}, + {0x91, _xInvalidOpHanlder}, + {0x92, _xInvalidOpHanlder}, + {0x93, _xInvalidOpHanlder}, + {0x94, _xInvalidOpHanlder}, + {0x95, _xInvalidOpHanlder}, + {0x96, _xInvalidOpHanlder}, + {0x97, _xInvalidOpHanlder}, + {0x98, _xDecodeOpEn_ZO}, + {0x99, _xDecodeOpEn_ZO}, +#if defined(_M_X64) || defined(__x86_64__) + {0x9A, _xInvalidOpHanlder}, +#else + {0x9A, _xDecodeOpEn_ZO}, +#endif + {0x9B, _xDecodeOpEn_ZO}, + {0x9C, _xDecodeOpEn_ZO}, + {0x9D, _xDecodeOpEn_ZO}, + {0x9E, _xDecodeOpEn_ZO}, + {0x9F, _xDecodeOpEn_ZO}, + {0xA0, _xUnknownOpHanlder}, + {0xA1, _xUnknownOpHanlder}, + {0xA2, _xUnknownOpHanlder}, + {0xA3, _xUnknownOpHanlder}, + {0xA4, _xDecodeOpEn_ZO}, + {0xA5, _xDecodeOpEn_ZO}, + {0xA6, _xDecodeOpEn_ZO}, + {0xA7, _xDecodeOpEn_ZO}, + {0xA8, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0xA9, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, + {0xAA, _xDecodeOpEn_ZO}, + {0xAB, _xDecodeOpEn_ZO}, + {0xAC, _xDecodeOpEn_ZO}, + {0xAD, _xDecodeOpEn_ZO}, + {0xAE, _xDecodeOpEn_ZO}, + {0xAF, _xDecodeOpEn_ZO}, +#undef SAME_ITEM_LAZY +#define SAME_ITEM_LAZY 1, OpEn_OI, OpSz_0, ImmSz_8, _DecodeOpEn_OI + {0xB0, SAME_ITEM_LAZY}, + {0xB1, SAME_ITEM_LAZY}, + {0xB2, SAME_ITEM_LAZY}, + {0xB3, SAME_ITEM_LAZY}, + {0xB4, SAME_ITEM_LAZY}, + {0xB5, SAME_ITEM_LAZY}, + {0xB6, SAME_ITEM_LAZY}, + {0xB7, SAME_ITEM_LAZY}, +#undef SAME_ITEM_LAZY +#define SAME_ITEM_LAZY 1, OpEn_OI, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_OI + {0xB8, SAME_ITEM_LAZY}, + {0xB9, SAME_ITEM_LAZY}, + {0xBA, SAME_ITEM_LAZY}, + {0xBB, SAME_ITEM_LAZY}, + {0xBC, SAME_ITEM_LAZY}, + {0xBD, SAME_ITEM_LAZY}, + {0xBE, SAME_ITEM_LAZY}, + {0xBF, SAME_ITEM_LAZY}, + {0xC0, 2, OpEn_MI, OpSz_8, ImmSz_8, _DecodeOpEn_MI}, + {0xC1, 2, OpEn_MI, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_MI}, + {0xC2, 1, OpEn_I, OpSz_0, ImmSz_16, _DecodeOpEn_I}, + {0xC3, _xDecodeOpEn_ZO}, + {0xC4, _xInvalidOpHanlder}, + {0xC5, _xInvalidOpHanlder}, + {0xC6, _xUnknownOpHanlder}, + {0xC7, 2, OpEn_MI, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_MI}, + {0xC8, _xDecodeOpC8}, + {0xC9, _xDecodeOpEn_ZO}, + {0xCA, 1, OpEn_I, OpSz_0, ImmSz_16, _DecodeOpEn_I}, + {0xCB, _xDecodeOpEn_ZO}, + {0xCC, _xDecodeOpEn_ZO}, + {0xCD, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, +#if defined(_M_X64) || defined(__x86_64__) + {0xCE, _xInvalidOpHanlder}, +#else + {0xCE, _xDecodeOpEn_ZO}, +#endif + {0xCF, _xDecodeOpEn_ZO}, + {0xD0, 1, OpEn_M1, OpSz_8, ImmSz_0, _DecodeOpEn_M1}, + {0xD1, 1, OpEn_M1, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_M1}, + {0xD2, 1, OpEn_MC, OpSz_8, ImmSz_0, _DecodeOpEn_MC}, + {0xD3, 1, OpEn_MC, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_MC}, +#if defined(_M_X64) || defined(__x86_64__) + {0xD4, _xInvalidOpHanlder}, + {0xD5, _xInvalidOpHanlder}, +#else + {0xD4, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0xD5, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, +#endif + {0xD6, _xInvalidOpHanlder}, + {0xD7, _xDecodeOpEn_ZO}, + {0xD8, _xUnknownOpHanlder}, + {0xD9, _xUnknownOpHanlder}, + {0xDA, _xUnknownOpHanlder}, + {0xDB, _xUnknownOpHanlder}, + {0xDC, _xUnknownOpHanlder}, + {0xDD, _xUnknownOpHanlder}, + {0xDE, _xUnknownOpHanlder}, + {0xDF, _xUnknownOpHanlder}, + {0xE0, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0xE1, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0xE2, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0xE3, 1, OpEn_D, OpSz_0, ImmSz_8, _DecodeOpEn_D}, + {0xE4, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0xE5, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0xE6, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0xE7, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0xE8, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, + {0xE9, 1, OpEn_I, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_I}, +#if defined(_M_X64) || defined(__x86_64__) + {0xEA, _xInvalidOpHanlder}, +#else + {0xEA, _xUnknownOpHanlder}, +#endif + {0xEB, 1, OpEn_I, OpSz_0, ImmSz_8, _DecodeOpEn_I}, + {0xEC, _xDecodeOpEn_ZO}, + {0xED, _xDecodeOpEn_ZO}, + {0xEE, _xDecodeOpEn_ZO}, + {0xEF, _xDecodeOpEn_ZO}, + {0xF0, _xDecodePrefix}, + {0xF1, _xDecodeOpEn_ZO}, + {0xF2, _xDecodeOpEn_ZO}, +#ifdef DETOURS_X86 + {0xF3, _CopyF3}, +#else + {0xF3, _xDecodeOpEn_ZO}, +#endif + {0xF4, _xDecodeOpEn_ZO}, + {0xF5, _xDecodeOpEn_ZO}, + {0xF6, 2, OpEn_MI, OpSz_8, ImmSz_8, _DecodeOpEn_MI}, + {0xF7, 2, OpEn_MI, OpSz_16 | OpSz_32, ImmSz_16 | ImmSz_32, _DecodeOpEn_MI}, + {0xF8, _xDecodeOpEn_ZO}, + {0xF9, _xDecodeOpEn_ZO}, + {0xFA, _xDecodeOpEn_ZO}, + {0xFB, _xDecodeOpEn_ZO}, + {0xFC, _xDecodeOpEn_ZO}, + {0xFD, _xDecodeOpEn_ZO}, + {0xFE, 2, OpEn_M, OpSz_8, ImmSz_0, _DecodeOpEn_M}, + {0xFF, 2, OpEn_M, OpSz_16 | OpSz_32, ImmSz_0, _DecodeOpEn_M}, + {0, 0, 0, 0, 0}}; + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/X86OpcodoDecodeTable.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/X86OpcodoDecodeTable.h new file mode 100644 index 0000000..778fdb3 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/deprecated/X86OpcodoDecodeTable.h @@ -0,0 +1,142 @@ +#ifndef X86_OPCODE_DECODE_TABLE_H +#define X86_OPCODE_DECODE_TABLE_H + +#ifndef __addr_t_defined +#define __addr_t_defined +typedef unsigned long long addr_t; +#endif + +#ifndef __byte_defined +#define __byte_defined +typedef unsigned char byte_t; +#endif + +#ifndef __uint_defined +#define __uint_defined +typedef unsigned int uint; +#endif + +#ifndef __word_defined +#define __word_defined +typedef short word; +#endif + +#ifndef __dword_defined +#define __dword_defined +typedef int dword; +#endif + +enum OpcodeType { OpTy_Op1, OpTy_RegInOp1, OpTy_Op1ExtraOp }; + +struct Instr { + byte_t prefix; + + byte_t REX; + + union { + byte_t opcode[3]; + struct { + byte_t opcode1; + byte_t opcode2; + byte_t opcode3; + }; + }; + + union { + byte_t ModRM; + struct { + byte_t Mod : 2; + byte_t RegOpcode : 3; + byte_t RM : 3; + }; + }; + + union { + byte_t SIB; + struct { + byte_t base : 2; + byte_t index : 3; + byte_t scale : 3; + }; + }; + + byte_t Displacement[4]; + int DisplacementOffset; + + byte_t Immediate[4]; + int ImmediateOffset; +}; + +// clang-format off +enum OperandSize { + OpSz_0 = 0, + OpSz_8=1, + OpSz_16=2, + OpSz_32=4, + OpSz_64=8 +}; + +enum ImmediteSize { + ImmSz_0 = 0, + ImmSz_8=1, + ImmSz_16=2, + ImmSz_32=4, + ImmSz_64=8 +}; + +enum InstrFlag { + kNoFlag = 0, + kIPRelativeAddress = 1 +}; +// clang-format on + +struct InstrMnemonic { + uint len; + + int flag; + + OperandSize OperandSz; + + ImmediteSize ImmediteSz; + + struct Instr instr; +}; + +struct OpcodeDecodeItem { + unsigned char opcode; + + int FixedSize; + + int OpEn; + + int OperandSz; + + int ImmediteSz; + + void (*DecodeHandler)(InstrMnemonic *, addr_t); +}; + +// clang-format off +enum OperandEncodingType { + OpEn_NONE =0, + OpEn_ZO, + OpEn_M, + OpEn_I, + OpEn_D, + OpEn_O, + OpEn_RM, + OpEn_MR, + OpEn_MI, + OpEn_OI, + OpEn_M1, + OpEn_MC, + OpEn_RMI +}; + +// clang-format on + +extern OpcodeDecodeItem OpcodeDecodeTable[257]; + +void _DecodePrefix(InstrMnemonic *instr, addr_t p); + +#endif diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/build_config.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/build_config.h new file mode 100644 index 0000000..7c558c2 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/build_config.h @@ -0,0 +1,144 @@ +#ifndef BUILD_CONFIG_H +#define BUILD_CONFIG_H + +#if defined(__APPLE__) +// only include TargetConditions after testing ANDROID as some android builds +// on mac don't have this header available and it's not needed unless the target +// is really mac/ios. +#include +#define OS_MACOSX 1 +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#define OS_IOS 1 +#endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#elif defined(__linux__) +#define OS_LINUX 1 +// include a system header to pull in features.h for glibc/uclibc macros. +#include +#if defined(__GLIBC__) && !defined(__UCLIBC__) +// we really are using glibc, not uClibc pretending to be glibc +#define LIBC_GLIBC 1 +#endif +#elif defined(_WIN32) +#define OS_WIN 1 +#elif defined(__Fuchsia__) +#define OS_FUCHSIA 1 +#elif defined(__FreeBSD__) +#define OS_FREEBSD 1 +#elif defined(__NetBSD__) +#define OS_NETBSD 1 +#elif defined(__OpenBSD__) +#define OS_OPENBSD 1 +#elif defined(__sun) +#define OS_SOLARIS 1 +#elif defined(__QNXNTO__) +#define OS_QNX 1 +#elif defined(_AIX) +#define OS_AIX 1 +#elif defined(__asmjs__) || defined(__wasm__) +#define OS_ASMJS +#else +#error Please add support for your platform in build/build_config.h +#endif +// NOTE: Adding a new port? Please follow +// https://chromium.googlesource.com/chromium/src/+/master/docs/new_port_policy.md + +// For access to standard BSD features, use OS_BSD instead of a +// more specific macro. +#if defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_OPENBSD) +#define OS_BSD 1 +#endif + +// For access to standard POSIXish features, use OS_POSIX instead of a +// more specific macro. +#if defined(OS_AIX) || defined(OS_ANDROID) || defined(OS_ASMJS) || defined(OS_FREEBSD) || defined(OS_LINUX) || \ + defined(OS_MACOSX) || defined(OS_NACL) || defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_QNX) || \ + defined(OS_SOLARIS) +#define OS_POSIX 1 +#endif + +// Compiler detection. Note: clang masquerades as GCC on POSIX and as MSVC on +// Windows. +#if defined(__GNUC__) +#define COMPILER_GCC 1 +#elif defined(_MSC_VER) +#define COMPILER_MSVC 1 +#else +#error Please add support for your compiler in build/build_config.h +#endif + +// Processor architecture detection. For more info on what's defined, see: +// http://msdn.microsoft.com/en-us/library/b0084kay.aspx +// http://www.agner.org/optimize/calling_conventions.pdf +// or with gcc, run: "echo | gcc -E -dM -" +#if defined(_M_X64) || defined(__x86_64__) +#define ARCH_CPU_X86_FAMILY 1 +#define ARCH_CPU_X86_64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(_M_IX86) || defined(__i386__) +#define ARCH_CPU_X86_FAMILY 1 +#define ARCH_CPU_X86 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__s390x__) +#define ARCH_CPU_S390_FAMILY 1 +#define ARCH_CPU_S390X 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#elif defined(__s390__) +#define ARCH_CPU_S390_FAMILY 1 +#define ARCH_CPU_S390 1 +#define ARCH_CPU_31_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#elif (defined(__PPC64__) || defined(__PPC__)) && defined(__BIG_ENDIAN__) +#define ARCH_CPU_PPC64_FAMILY 1 +#define ARCH_CPU_PPC64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#elif defined(__PPC64__) +#define ARCH_CPU_PPC64_FAMILY 1 +#define ARCH_CPU_PPC64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#define ARCH_CPU_ARMEL 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__aarch64__) || defined(_M_ARM64) +#define ARCH_CPU_ARM_FAMILY 1 +#define ARCH_CPU_ARM64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__pnacl__) || defined(__asmjs__) || defined(__wasm__) +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__MIPSEL__) +#if defined(__LP64__) +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPS64EL 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#else +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPSEL 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#endif +#elif defined(__MIPSEB__) +#if defined(__LP64__) +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPS64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#else +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPS 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#endif +#else +#error Please add support for your architecture in build/build_config.h +#endif + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.c b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.c new file mode 100644 index 0000000..1b5de10 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.c @@ -0,0 +1,564 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) + +#include "x86_insn_decode.h" + +#include "logging/logging.h" + +#define REX_W(byte) ((byte & 0b00001000) >> 3) +#define REX_R(byte) ((byte & 0b00000100) >> 2) +#define REX_X(byte) ((byte & 0b00000010) >> 1) +#define REX_B(byte) ((byte & 0b00000001) >> 0) + +#define ModRM_Mod(byte) ((byte & 0b11000000) >> 6) +#define ModRM_RegOpcode(byte) ((byte & 0b00111000) >> 3) +#define ModRM_RM(byte) (byte & 0b00000111) + +#define SIB_Scale(sib) ((sib & 0b11000000) >> 6) +#define SIB_Index(sib) ((sib & 0b00111000) >> 3) +#define SIB_Base(sib) ((sib & 0b00000111) >> 0) + +#if 0 +/* Build an encoding specification from scratch. */ +#define SPEC_MAKE(op, opr1, opr2, opr3, opr4) \ + ((uint64_t)(uint16_t)(int16_t)(op) | ((uint64_t)(opr1) << 16) | ((uint64_t)(opr2) << 24) | \ + ((uint64_t)(opr3) << 32) | ((uint64_t)(opr4) << 40)) + +/* Get the operation in an encoding specification. */ +#define SPEC_INSN(spec) ((int16_t)((spec)&0xffff)) + +/* Get the given operand (zero-based) in an encoding specification. */ +#define SPEC_OPERAND(spec, i) ((uint8_t)(((spec) >> (16 + (i)*8)) & 0xff)) + +/* Get the operands part of an encoding specification. */ +#define SPEC_OPERANDS(spec) ((spec)&0xffffffffffff0000ULL) + +/* Merges two encoding specifications. */ +#define SPEC_MERGE(spec1, spec2) ((spec1) | (spec2)) + +#define OP4(insn, oper1, oper2, oper3, oper4) SPEC_MAKE(I_##insn, O_##oper1, O_##oper2, O_##oper3, O_##oper4) +#define OP3(insn, oper1, oper2, oper3) OP4(insn, oper1, oper2, oper3, NONE) +#define OP2(insn, oper1, oper2) OP3(insn, oper1, oper2, NONE) +#define OP1(insn, oper1) OP2(insn, oper1, NONE) +#define OP0(insn) OP1(insn, NONE) +#define OP_EMPTY OP0(NONE) +#define OP_EMPTY_4 OP_EMPTY, OP_EMPTY, OP_EMPTY, OP_EMPTY +#define OP_EMPTY_8 OP_EMPTY_4, OP_EMPTY_4 +#endif + +#define op3_flag(x, f, o0, o1, o2) \ + { \ + .name = #x, .flags = (f), .operands[0] = {.data = #o0}, .operands[1] = {.data = #o1}, \ + .operands[2] = {.data = #o2}, \ + } +#define op2_flag(x, f, o0, o1) op3_flag(x, f, o0, o1, __) +#define op1_flag(x, f, o0) op2_flag(x, f, o0, __) +#define op0_flag(x, f) op1_flag(x, f, __) + +#define op3f op3_flag +#define op2f op2_flag +#define op1f op1_flag +#define op0f op0_flag + +#define op3(x, o0, o1, o2) op3f(x, 0, o0, o1, o2) +#define op2(x, o0, o1) op2f(x, 0, o0, o1) +#define op1(x, o0) op1f(x, 0, o0) +#define op0(x) op0f(x, 0) + +/* Opcode extension in modrm byte reg field. */ +#define foreach_x86_insn_modrm_reg_group \ + _(1) _(1a) _(2) _(3) _(4) _(5) _(6) _(7) _(8) _(9) _(10) _(11) _(12) _(13) _(14) _(15) _(16) _(p) +#define foreach_x86_insn_sse_group \ + _(10) _(28) _(50) _(58) _(60) _(68) _(70) _(78) _(c0) _(d0) _(d8) _(e0) _(e8) _(f0) _(f8) +enum { + X86_INSN_GROUP_START = 0, + +#define _(x) X86_INSN_MODRM_REG_GROUP_##x, + foreach_x86_insn_modrm_reg_group +#undef _ + + X86_INSN_SSE_GROUP_START = 19, +#define _(x) X86_INSN_SSE_GROUP_##x, + foreach_x86_insn_sse_group +#undef _ + + X86_INSN_GROUP_END = 35 +}; + +#define X86_INSN_GROUP_END_MASK ((1 << 6) - 1) +#define X86_INSN_FLAG_SET_GROUP(n) ((n) << 5) +#define X86_INSN_FLAG_GET_GROUP(f) (((f) >> 5) & X86_INSN_GROUP_END_MASK) + +enum { +#define _(x) X86_INSN_FLAG_MODRM_REG_GROUP_##x = X86_INSN_FLAG_SET_GROUP(X86_INSN_MODRM_REG_GROUP_##x), + foreach_x86_insn_modrm_reg_group +#undef _ + +#define _(x) X86_INSN_FLAG_SSE_GROUP_##x = X86_INSN_FLAG_SET_GROUP(X86_INSN_SSE_GROUP_##x), + foreach_x86_insn_sse_group +#undef _ +}; + +// clang-format off + +#define foreach_x86_operand_combine(x, op1_type, op2_type) op2(x, Eb, Gb), op2(x, Ev, Gv), op2(x, Gb, Eb), op2(x, Gv, Ev), op2(x, AL, Ib), op2(x, AX, Iz) + +#define foreach_x86_gp_reg _(AX) _(CX) _(DX) _(BX) _(SP) _(BP) _(SI) _(DI) + +#define foreach_x86_condition _(o) _(no) _(b) _(nb) _(z) _(nz) _(be) _(nbe) _(s) _(ns) _(p) _(np) _(l) _(nl) _(le) _(nle) + +// clang-format on + +#include "./x86_opcode_one_byte.c" +#include "./x86_opcode_two_byte.c" + +typedef struct { + x86_insn_spec_t insns[8]; +} x86_insn_group8_t; + +#include "./x86_opcode_modrm_reg_group.c" +#include "./x86_opcode_sse_group.c" + +#include "./x86_insn_reader.c" + +static x86_insn_prefix_t x86_insn_decode_prefix(x86_insn_reader_t *rd, x86_insn_decode_t *insn, x86_options_t *conf) { + /* Decode each byte until the byte is not a prefix or is an REX prefix, + * because an REX prefix is required to immediately preceed the opcode. + */ + x86_insn_prefix_t insn_prefix = 0; + for (;;) { + uint8_t c = peek_byte(rd); + x86_insn_prefix_t t = 0; + + /* Check for REX prefix if we're in 64-bit mode. */ + if (conf->mode == 64) { + if (c >= 0x40 && c <= 0x4f) { + uint8_t rex = read_byte(rd); + + if (REX_W(rex)) { + insn->flags |= X86_INSN_DECODE_FLAG_OPERAND_SIZE_64; + } + + insn->rex = rex; + + break; + } + } + + /* Check for legacy prefixes. */ + switch (c) { + case 0xF0: + t = INSN_PREFIX_LOCK; + break; + case 0xF2: + t = INSN_PREFIX_REPNE; + break; + case 0xF3: + t = INSN_PREFIX_REPE; + break; + case 0x2E: + t = INSN_PREFIX_CS; + break; + case 0x36: + t = INSN_PREFIX_SS; + break; + case 0x3E: + t = INSN_PREFIX_DS; + break; + case 0x26: + t = INSN_PREFIX_ES; + break; + case 0x64: + t = INSN_PREFIX_FS; + break; + case 0x65: + t = INSN_PREFIX_GS; + break; + case 0x66: + t = INSN_PREFIX_OPERAND_SIZE; + break; + case 0x67: + t = INSN_PREFIX_ADDRESS_SIZE; + break; + } + if (t == 0) + break; + + /* Consume 1 byte. */ + read_byte(rd); + insn_prefix |= t; + } + + return insn_prefix; +} + +int x86_insn_has_modrm_byte(x86_insn_spec_t *insn) { + int i; + for (i = 0; i < sizeof(insn->operands) / sizeof(x86_insn_operand_spec_t); i++) + switch (insn->operands[i].code) { + case 'G': + case 'E': + case 'M': + case 'R': + return 1; + } + return 0; +} + +int x86_insn_immediate_type(x86_insn_spec_t *insn) { + int i; + for (i = 0; i < sizeof(insn->operands); i++) { + switch (insn->operands[i].code) { + case 'J': + case 'I': + case 'O': + return insn->operands[i].type; + } + } + return 0; +} + +int x86_insn_has_immediate(x86_insn_spec_t *insn) { + int i; + for (i = 0; i < sizeof(insn->operands) / sizeof(x86_insn_operand_spec_t); i++) { + switch (insn->operands[i].code) { + case 'J': + case 'I': + case 'O': + return 1; + } + } + return 0; +} + +static uint8_t *x86_insn_decode_number(x86_insn_reader_t *rd, uint8_t number_bits, int64_t *out_number) { + int64_t disp = 0; + switch (number_bits) { + case 64: + disp = read_uint64(rd); + break; + case 32: + disp = read_uint32(rd); + break; + case 16: + disp = read_uint16(rd); + break; + case 8: + disp = read_uint8(rd); + break; + default: + UNREACHABLE(); + } + + *out_number = disp; + return NULL; +} + +void x86_insn_decode_modrm_sib(x86_insn_reader_t *rd, x86_insn_decode_t *insn, x86_options_t *conf) { + uint8_t mod, rm, reg; + + x86_insn_modrm_t modrm; + modrm.byte = read_byte(rd); + insn->modrm = modrm; + + mod = modrm.mode; + rm = (uint8_t)((REX_B(insn->rex) << 3) | modrm.rm); + reg = (uint8_t)((REX_R(insn->rex) << 3) | modrm.reg); + + x86_insn_operand_t *reg_op = &insn->operands[0]; + x86_insn_operand_t *mem_op = &insn->operands[1]; + + reg_op->reg = reg; + + if (mod == 3) { + mem_op->reg = rm; + return; + } + + uint8_t disp_bits = -1; + + insn->flags |= X86_INSN_DECODE_FLAG_IS_ADDRESS; + + uint8_t effective_address_bits; + if (conf->mode == 64) + effective_address_bits = (insn->prefix & INSN_PREFIX_ADDRESS_SIZE) ? 32 : 64; + else if (conf->mode == 32) + effective_address_bits = (insn->prefix & INSN_PREFIX_ADDRESS_SIZE) ? 16 : 32; + else { + FATAL("16-bit address mode not supported"); + } + + if (effective_address_bits == 32 || effective_address_bits == 64) { + mem_op->mem.base = rm; + + insn->flags |= X86_INSN_DECODE_FLAG_HAS_BASE; + + if (mod == 0 && (rm & 7) == 5) { + insn->flags = X86_INSN_DECODE_FLAG_IP_RELATIVE; + mem_op->mem.base = RIP; + disp_bits = 32; + } else if (mod == 0) { + disp_bits = 0; + } else if (mod == 1) { + disp_bits = 8; + } else if (mod == 2) { + disp_bits = 32; + } else { + disp_bits = 0; + } + + uint8_t has_sib = 0; + if ((rm & 7) == 4) { + ASSERT(modrm.rm == (rm & 7)); + has_sib = 1; + } + + if (has_sib) { + x86_insn_sib_t sib = {0}; + sib.byte = read_byte(rd); + insn->sib = sib; + + uint8_t base = (uint8_t)(sib.base | (REX_B(insn->rex) << 3)); + uint8_t index = (uint8_t)(sib.index | (REX_X(insn->rex) << 3)); + uint8_t scale = (uint8_t)(1 << sib.log2_scale); + + insn->flags |= X86_INSN_DECODE_FLAG_HAS_BASE; + + if (sib.index != X86_INSN_GP_REG_SP) { + insn->flags |= X86_INSN_DECODE_FLAG_HAS_INDEX; + } + + insn->operands[1].mem.base = base; + insn->operands[1].mem.index = index; + insn->operands[1].mem.scale = scale; + + if (sib.index == X86_INSN_GP_REG_SP) { + insn->operands[1].mem.index = RNone; + insn->operands[1].mem.scale = 0; + } + + // for 64 bit + if (effective_address_bits == 64) { + if (mem_op->mem.base == RBP || mem_op->mem.base == R13) { + if (mod == 0) { + mem_op->mem.base = RNone; + } + if (mod == 1) { + disp_bits = 8; + } else { + disp_bits = 32; + } + } + + if (sib.index != X86_INSN_GP_REG_SP) { + insn->flags |= X86_INSN_DECODE_FLAG_HAS_INDEX; + } + } + + // for 32 bit + if (effective_address_bits == 32) { + if (mem_op->mem.base == RBP) { + if (mod == 0) { + mem_op->mem.base = RNone; + } + if (mod == 1) { + disp_bits = 8; + } else { + disp_bits = 32; + } + } + } + } + } + + // for 16 bit + if (effective_address_bits == 16) { + switch (modrm.mode) { + case 0: + if (modrm.rm == 6) { + /* [disp16] */ + disp_bits = 16; + break; + } + /* fall through */ + case 1: + case 2: + switch (modrm.rm) { + case 0: /* [bx + si/di] */ + case 1: + mem_op->mem.base = X86_INSN_GP_REG_BX; + mem_op->mem.index = X86_INSN_GP_REG_SI + (modrm.rm & 1); + insn->flags |= X86_INSN_DECODE_FLAG_HAS_BASE | X86_INSN_DECODE_FLAG_HAS_INDEX; + break; + + case 2: /* [bp + si/di] */ + case 3: + mem_op->mem.base = X86_INSN_GP_REG_BP; + mem_op->mem.index = X86_INSN_GP_REG_SI + (modrm.rm & 1); + insn->flags |= X86_INSN_DECODE_FLAG_HAS_BASE | X86_INSN_DECODE_FLAG_HAS_INDEX; + break; + + case 4: /* [si/di] */ + case 5: + mem_op->mem.base = X86_INSN_GP_REG_SI + (modrm.rm & 1); + insn->flags |= X86_INSN_DECODE_FLAG_HAS_BASE; + break; + + case 6: /* [bp + disp] */ + mem_op->mem.base = X86_INSN_GP_REG_BP; + insn->flags |= X86_INSN_DECODE_FLAG_HAS_BASE; + break; + + case 7: /* [bx + disp] */ + mem_op->mem.base = X86_INSN_GP_REG_BX; + insn->flags |= X86_INSN_DECODE_FLAG_HAS_BASE; + break; + } + + if (modrm.mode != 0) + disp_bits = modrm.mode == 1 ? 8 : 16; + break; + } + } + + if (disp_bits != 0) { + // update displacement offset + insn->displacement_offset = (uint8_t)reader_offset(rd); + + int64_t disp; + x86_insn_decode_number(rd, disp_bits, &disp); + mem_op->mem.disp = disp; + } +} + +/* Decodes the opcode of an instruction and returns its encoding + * specification. + */ +static void x86_insn_decode_opcode(x86_insn_reader_t *rd, x86_insn_decode_t *insn, x86_options_t *conf) { + uint8_t opcode = read_byte(rd); + + x86_insn_spec_t insn_spec; + if (opcode == 0x0f) { + opcode = read_byte(rd); + insn_spec = x86_opcode_map_two_byte[opcode]; + } else { + insn_spec = x86_opcode_map_one_byte[opcode]; + } + + // check sse group + if (X86_INSN_FLAG_GET_GROUP(insn_spec.flags) > X86_INSN_SSE_GROUP_START) { + UNIMPLEMENTED(); + } + + if (X86_INSN_FLAG_GET_GROUP(insn_spec.flags) > X86_INSN_GROUP_START && + X86_INSN_FLAG_GET_GROUP(insn_spec.flags) < X86_INSN_SSE_GROUP_START) { + // get group index + int group_ndx = X86_INSN_FLAG_GET_GROUP(insn_spec.flags); + + // get gp insn index in group + x86_insn_modrm_t modrm; + modrm.byte = peek_byte(rd); + int insn_ndx = modrm.reg; + + // get insn in group + x86_insn_spec_t *group_insn = NULL; + group_insn = &x86_insn_modrm_reg_groups[group_ndx].insns[insn_ndx]; + + // update the insn spec + insn_spec.name = group_insn->name; + insn_spec.flags = group_insn->flags; + } + + insn->primary_opcode = opcode; + insn->insn_spec = insn_spec; +} + +uint8_t x86_insn_imm_bits(x86_insn_spec_t *insn, uint8_t operand_bits) { + uint8_t imm_bits = 0; + switch (x86_insn_immediate_type(insn)) { + case 'b': + imm_bits = 8; + break; + case 'w': + imm_bits = 16; + break; + case 'd': + imm_bits = 32; + break; + case 'q': + imm_bits = 64; + break; + + case 'z': + imm_bits = operand_bits; + if (imm_bits == 64) + imm_bits = 32; + break; + + case 'v': + imm_bits = operand_bits; + break; + + default: + imm_bits = 0; + break; + } + + return imm_bits; +} + +void x86_insn_decode_immediate(x86_insn_reader_t *rd, x86_insn_decode_t *insn, x86_options_t *conf) { + uint8_t effective_operand_bits; + if (conf->mode == 64 || conf->mode == 32) { + effective_operand_bits = (insn->prefix & INSN_PREFIX_OPERAND_SIZE) ? 16 : 32; + } + effective_operand_bits = (insn->prefix & INSN_PREFIX_OPERAND_SIZE) ? 16 : 32; + + if (insn->flags & X86_INSN_DECODE_FLAG_OPERAND_SIZE_64) + effective_operand_bits = 64; + + if (conf->mode == 64 && insn->insn_spec.flags & X86_INSN_SPEC_DEFAULT_64_BIT) + effective_operand_bits = 64; + + int64_t immediate = 0; + uint8_t imm_bits = x86_insn_imm_bits(&insn->insn_spec, effective_operand_bits); + if (imm_bits == 0) + return; + + // update immediate offset + insn->immediate_offset = (uint8_t)reader_offset(rd); + + x86_insn_decode_number(rd, imm_bits, &immediate); + insn->immediate = immediate; +} + +void x86_insn_decode(x86_insn_decode_t *insn, uint8_t *buffer, x86_options_t *conf) { + // init reader + x86_insn_reader_t rd; + init_reader(&rd, buffer, buffer + 15); + + // decode prefix + insn->prefix = x86_insn_decode_prefix(&rd, insn, conf); + + // decode insn specp/x in + x86_insn_decode_opcode(&rd, insn, conf); + + if (x86_insn_has_modrm_byte(&insn->insn_spec)) { + // decode insn modrm sib (operand register, disp) + x86_insn_decode_modrm_sib(&rd, insn, conf); + } + + if (x86_insn_has_immediate(&insn->insn_spec)) { + // decode insn immeidate + x86_insn_decode_immediate(&rd, insn, conf); + } + +#if 1 + DLOG(0, "[x86 insn] %s", insn->insn_spec.name); +#endif + + // set insn length + insn->length = rd.buffer_cursor - rd.buffer; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h new file mode 100644 index 0000000..bb395fd --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h @@ -0,0 +1,200 @@ +#ifndef X86_INSN_DECODE_H +#define X86_INSN_DECODE_H + +#include +#include "common_header.h" + +typedef enum { + X86_INSN_SPEC_DEFAULT_64_BIT = 1 << 0, +} x86_insn_spec_flag_t; + +typedef enum { + X86_INSN_DECODE_FLAG_HAS_BASE = 1 << 0, + + X86_INSN_DECODE_FLAG_HAS_INDEX = 1 << 1, + + X86_INSN_DECODE_FLAG_IS_ADDRESS = 1 << 2, + + X86_INSN_DECODE_FLAG_IP_RELATIVE = 1 << 3, + + X86_INSN_DECODE_FLAG_OPERAND_SIZE_64 = 1 << 4, +} x86_insn_decode_flag_t; + +typedef enum { + INSN_PREFIX_NONE = 0, + + /* Group 1: lock and repeat prefixes */ + INSN_PREFIX_GROUP1 = 0x07, + INSN_PREFIX_LOCK = 0x01, /* F0 */ + INSN_PREFIX_REPNZ = 0x02, /* F2 */ + INSN_PREFIX_REPNE = INSN_PREFIX_REPNZ, + INSN_PREFIX_REP = 0x04, /* F3 */ + INSN_PREFIX_REPZ = INSN_PREFIX_REP, + INSN_PREFIX_REPE = INSN_PREFIX_REPZ, + + /* Group 2: segment override or branch hints */ + INSN_PREFIX_GROUP2 = 0x01f8, + INSN_PREFIX_ES = 0x0008, /* 26 */ + INSN_PREFIX_CS = 0x0010, /* 2E */ + INSN_PREFIX_SS = 0x0020, /* 36 */ + INSN_PREFIX_DS = 0x0040, /* 3E */ + INSN_PREFIX_FS = 0x0080, /* 64 */ + INSN_PREFIX_GS = 0x0100, /* 65 */ + INSN_PREFIX_BRANCH_TAKEN = INSN_PREFIX_CS, /* 2E */ + INSN_PREFIX_BRANCH_NOT_TAKEN = INSN_PREFIX_DS, /* 3E */ + + /* Group 3: operand-size override */ + INSN_PREFIX_OPERAND_SIZE = 0x0200, /* 66 */ + + /* Group 4: address-size override */ + INSN_PREFIX_ADDRESS_SIZE = 0x0400 /* 67 */ +} x86_insn_prefix_t; + +typedef union { + struct { + uint8_t code; + uint8_t type; + }; + uint8_t data[2]; +} x86_insn_operand_spec_t; + +typedef struct { + // insn name + char *name; + + // insn max 3 operands + x86_insn_operand_spec_t operands[3]; + + // insn flag + uint16_t flags; +#define X86_INSN_FLAG_SET_SSE_GROUP(n) ((n) << 5) +#define X86_INSN_FLAG_GET_SSE_GROUP(f) (((f) >> 5) & 0x1f) +#define X86_INSN_FLAG_SET_MODRM_REG_GROUP(n) (((n)&0x3f) << 10) +#define X86_INSN_FLAG_GET_MODRM_REG_GROUP(f) (((f) >> 10) & 0x3f) +} x86_insn_spec_t; + +#define foreach_x86_gp_register _(AX) _(CX) _(DX) _(BX) _(SP) _(BP) _(SI) _(DI) + +typedef enum { +#define _(r) X86_INSN_GP_REG_##r, + foreach_x86_gp_register +#undef _ +} x86_insn_gp_register_t; + +typedef enum { + RNone = 0, + RAX, + RBX, + RCX, + RDX, + RDI, + RSI, + RBP, + RSP, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, + RIP +} x86_ia32e_register_t; + +typedef union { + struct { + uint8_t rm : 3; + uint8_t reg : 3; + uint8_t mode : 2; + }; + uint8_t byte; +} x86_insn_modrm_t; + +typedef union { + struct { + uint8_t base : 3; + uint8_t index : 3; + uint8_t log2_scale : 2; + }; + uint8_t byte; +} x86_insn_sib_t; + +typedef struct { + uint8_t reg; + + struct { + uint8_t base; + uint8_t index; + uint8_t scale; + uint32_t disp; + } mem; +} x86_insn_operand_t; + +typedef struct x86_insn_decode_t { + // insn flag + uint32_t flags; + + // insn length + uint32_t length; + + // insn displacement offset + uint8_t displacement_offset; + + // insn immediate offset + uint8_t immediate_offset; + + // Registers in instruction + // [0] is modrm reg field + // [1] is base reg + // [2] is index reg + // union { + // struct { + // uint8_t modrm_reg; + // uint8_t op_base_reg; + // uint8_t op_index_reg; + // }; + // uint8_t regs[3]; + // }; + + x86_insn_operand_t operands[3]; + + struct { // insn field combine + // insn prefix + x86_insn_prefix_t prefix; + + // insn rex + uint8_t rex; + + // insn primary opcode + uint8_t primary_opcode; + + // insn modrm + x86_insn_modrm_t modrm; + + // insn sib + x86_insn_sib_t sib; + + // insn operand imm + int64_t immediate; + }; + + // insn pre-spec + x86_insn_spec_t insn_spec; +} x86_insn_decode_t; + +typedef struct x86_options_t { + int mode; /* 16, 32 or 64 bit */ +} x86_options_t; + +#ifdef __cplusplus +extern "C" { +#endif + +void x86_insn_decode(x86_insn_decode_t *insn, uint8_t *buffer, x86_options_t *conf); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_reader.c b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_reader.c new file mode 100644 index 0000000..059e547 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_insn_reader.c @@ -0,0 +1,87 @@ +/* Specialized instruction reader. */ +typedef struct x86_insn_reader_t { + const unsigned char *prefix; /* pointer to beginning of instruction */ + const unsigned char *opcode; /* pointer to opcode */ + const unsigned char *modrm; /* pointer to modrm byte */ + + unsigned char buffer[20]; /* buffer used when few bytes left */ + const unsigned char *buffer_cursor; /* pointer to buffer_cursor of insn + 1 */ +} x86_insn_reader_t; + +/* Initializes a bytecode reader to read code from a given part of memory. */ +static void init_reader(x86_insn_reader_t *rd, const unsigned char *begin, const unsigned char *buffer_cursor) { + if (buffer_cursor - begin < sizeof(rd->buffer)) { + memset(rd->buffer, 0xcc, sizeof(rd->buffer)); /* debug token */ + memcpy(rd->buffer, begin, buffer_cursor - begin); + rd->prefix = rd->buffer; + } else { + rd->prefix = begin; + } + rd->opcode = rd->modrm = rd->buffer_cursor = rd->prefix; +} + +uint32_t reader_offset(x86_insn_reader_t *rd) { + return rd->buffer_cursor - rd->buffer; +} + +static uint8_t peek_byte(const x86_insn_reader_t *rd) { + return *rd->buffer_cursor; +} + +#define read_uint8 read_byte +static uint8_t read_byte(x86_insn_reader_t *rd) { + DLOG(0, "[x86 insn reader] %p - 1", rd->buffer_cursor); + + const unsigned char *p = rd->buffer_cursor; + rd->buffer_cursor++; + return *p; +} + +#define read_uint16 read_word +static uint16_t read_word(x86_insn_reader_t *rd) { + DLOG(0, "[x86 insn reader] %p - 2", rd->buffer_cursor); + + const unsigned char *p = rd->buffer_cursor; + rd->buffer_cursor += 2; + return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); +} + +#define read_uint32 read_dword +static uint32_t read_dword(x86_insn_reader_t *rd) { + DLOG(0, "[x86 insn reader] %p - 4", rd->buffer_cursor); + + const unsigned char *p = rd->buffer_cursor; + rd->buffer_cursor += 4; + return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); +} + +#define read_uint64 read_qword +static uint64_t read_qword(x86_insn_reader_t *rd) { + DLOG(0, "[x86 insn reader] %p - 8", rd->buffer_cursor); + + uint64_t *p = (uint64_t *)rd->buffer_cursor; + rd->buffer_cursor += 4; + return p[0]; +} + +static uint32_t read_imm(x86_insn_reader_t *rd, int size) { + DLOG(0, "[x86 insn reader] %p", rd->buffer_cursor); + + return (size == 8) ? read_byte(rd) : (size == 16) ? read_word(rd) : (size == 32) ? read_dword(rd) : 0; +} + +static unsigned char read_modrm(x86_insn_reader_t *rd) { + if (rd->buffer_cursor == rd->modrm) + rd->buffer_cursor++; + return *rd->modrm; +} + +/* Marks the next byte as ModR/M. */ +static void continue_modrm(x86_insn_reader_t *rd) { + rd->modrm = rd->buffer_cursor; +} + +/* Marks the next byte as opcode. */ +static void continue_opcode(x86_insn_reader_t *rd) { + rd->modrm = rd->opcode = rd->buffer_cursor; +} diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_modrm_reg_group.c b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_modrm_reg_group.c new file mode 100644 index 0000000..352ea1a --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_modrm_reg_group.c @@ -0,0 +1,218 @@ +/* Escape groups are indexed by modrm reg field. */ +static x86_insn_group8_t x86_insn_modrm_reg_groups[] = { + [X86_INSN_MODRM_REG_GROUP_1].insns = + { + op0(add), + op0(or), + op0(adc), + op0(sbb), + op0(and), + op0(sub), + op0(xor), + op0(cmp), + }, + + [X86_INSN_MODRM_REG_GROUP_1a].insns = + { + op0f(pop, X86_INSN_SPEC_DEFAULT_64_BIT), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_2].insns = + { + op0(rol), + op0(ror), + op0(rcl), + op0(rcr), + op0(shl), + op0(shr), + op0(sal), + op0(sar), + }, + + [X86_INSN_MODRM_REG_GROUP_3].insns = + { + op0(test), + op0(test), + op0(not ), + op0(neg), + op0(mul), + op0(imul), + op0(div), + op0(idiv), + }, + + [X86_INSN_MODRM_REG_GROUP_4].insns = + { + op0(inc), + op0(dec), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_5].insns = + { + op1(inc, Ev), + op1(dec, Ev), + op1f(call, X86_INSN_SPEC_DEFAULT_64_BIT, Ev), + op1(call, Mp), + op1f(jmp, X86_INSN_SPEC_DEFAULT_64_BIT, Ev), + op1(jmp, Mp), + op1f(push, X86_INSN_SPEC_DEFAULT_64_BIT, Ev), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_6].insns = + { + op1(sldt, Ev), + op1(str, Ev), + op1(lldt, Ev), + op1(ltr, Ev), + op1(verr, Ev), + op1(verw, Ev), + op0(bad), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_7].insns = + { + op1(sgdt, Mv), + op1(sidt, Mv), + op1(lgdt, Mv), + op1(lidt, Mv), + op1(smsw, Ev), + op0(bad), + op1(lmsw, Ew), + op1(invlpg, Mv), + }, + + [X86_INSN_MODRM_REG_GROUP_8].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(bt, Ev, Ib), + op2(bts, Ev, Ib), + op2(btr, Ev, Ib), + op2(btc, Ev, Ib), + }, + + [X86_INSN_MODRM_REG_GROUP_9].insns = + { + op0(bad), + op1(cmpxchg, Mx), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_10].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_11].insns = + { + op0(mov), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_12].insns = + { + op0(bad), + op0(bad), + op2(psrlw, Rm, Ib), + op0(bad), + op2(psraw, Rm, Ib), + op0(bad), + op2(psllw, Rm, Ib), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_13].insns = + { + op0(bad), + op0(bad), + op2(psrld, Rm, Ib), + op0(bad), + op2(psrad, Rm, Ib), + op0(bad), + op2(pslld, Rm, Ib), + op0(bad), + }, + + [X86_INSN_MODRM_REG_GROUP_14].insns = + { + op0(bad), + op0(bad), + op2(psrlq, Rm, Ib), + op0f(bad, 0), + op0(bad), + op0(bad), + op2(psllq, Rm, Ib), + op0f(bad, 0), + }, + + [X86_INSN_MODRM_REG_GROUP_15].insns = + { + op1(fxsave, Mv), + op1(fxrstor, Mv), + op1(ldmxcsr, Mv), + op1(stmxcsr, Mv), + op0(bad), + op1(lfence, Mv), + op1(mfence, Mv), + op1(sfence, Mv), + }, + + [X86_INSN_MODRM_REG_GROUP_16].insns = + { + op1(prefetch_nta, Mv), + op1(prefetch_t0, Mv), + op1(prefetch_t1, Mv), + op1(prefetch_t2, Mv), + op1(prefetch_nop, Mv), + op1(prefetch_nop, Mv), + op1(prefetch_nop, Mv), + op1(prefetch_nop, Mv), + }, + + [X86_INSN_MODRM_REG_GROUP_p].insns = + { + op1(prefetch_exclusive, Mv), + op1(prefetch_modified, Mv), + op1(prefetch_nop, Mv), + op1(prefetch_modified, Mv), + op1(prefetch_nop, Mv), + op1(prefetch_nop, Mv), + op1(prefetch_nop, Mv), + op1(prefetch_nop, Mv), + }, +}; diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_one_byte.c b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_one_byte.c new file mode 100644 index 0000000..44b1462 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_one_byte.c @@ -0,0 +1,215 @@ +// clang-format off +static x86_insn_spec_t x86_opcode_map_one_byte[256] = { + /* 0x00 */ + foreach_x86_operand_combine(add, op_dst, op_src), + op0(push_es), + op0f(pop_es, X86_INSN_SPEC_DEFAULT_64_BIT), + foreach_x86_operand_combine(or, op_dst, op_src), + op0f(push_cs, X86_INSN_SPEC_DEFAULT_64_BIT), + op0(escape_two_byte), + + /* 0x10 */ + foreach_x86_operand_combine(adc, op_dst, op_src), + op0(push_ss), + op0(pop_ss), + foreach_x86_operand_combine(sbb, op_dst, op_src), + op0(push_ds), + op0(pop_ds), + + /* 0x20 */ + foreach_x86_operand_combine(and, op_dst, op_src), + op0(segment_es), + op0(daa), + foreach_x86_operand_combine(sub, op_dst, op_src), + op0(segment_cs), + op0(das), + + /* 0x30 */ + foreach_x86_operand_combine(xor, op_dst, op_src), + op0(segment_ss), + op0(aaa), + foreach_x86_operand_combine(cmp, op_src, op_src), + op0(segment_ds), + op0(aas), + +/* 0x40 */ +#define _(r) op1(inc, r), + foreach_x86_gp_reg +#undef _ +#define _(r) op1(dec, r), + foreach_x86_gp_reg +#undef _ + +/* 0x50 */ +#define _(r) op1f(push, X86_INSN_SPEC_DEFAULT_64_BIT, r), + foreach_x86_gp_reg +#undef _ +#define _(r) op1f(pop, X86_INSN_SPEC_DEFAULT_64_BIT, r), + foreach_x86_gp_reg +#undef _ + + /* 0x60 */ + op0(pusha), + op0(popa), + op2(bound, Gv, Ma), + op2(movsxd, Gv, Ed), + op0(segment_fs), + op0(segment_gs), + op0(operand_type), + op0(address_size), + op1f(push, X86_INSN_SPEC_DEFAULT_64_BIT, Iz), + op3(imul, Gv, Ev, Iz), + op1f(push, X86_INSN_SPEC_DEFAULT_64_BIT, Ib), + op3(imul, Gv, Ev, Ib), + op1(insb, DX), + op1(insw, DX), + op1(outsb, DX), + op1(outsw, DX), + +/* 0x70 */ +#define _(x) op1(j##x, Jb), + foreach_x86_condition +#undef _ + + /* 0x80 */ + op2f(modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Eb, Ib), + op2f(modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Ev, Iz), + op2f(modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Eb, Ib), + op2f(modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Ev, Ib), + op2(test, Eb, Gb), + op2(test, Ev, Gv), + op2(xchg, Eb, Gb), + op2(xchg, Ev, Gv), + op2(mov, Eb, Gb), + op2(mov, Ev, Gv), + op2(mov, Gb, Eb), + op2(mov, Gv, Ev), + op2(mov, Ev, Sw), + op2(lea, Gv, Ev), + op2(mov, Sw, Ew), + op1f(modrm_group_1a, X86_INSN_FLAG_MODRM_REG_GROUP_1a, Ev), + + /* 0x90 */ + op0(nop), + op1(xchg, CX), + op1(xchg, DX), + op1(xchg, BX), + op1(xchg, SP), + op1(xchg, BP), + op1(xchg, SI), + op1(xchg, DI), + op0(cbw), + op0(cwd), + op1(call, Ap), + op0(wait), + op0(pushf), + op0(popf), + op0(sahf), + op0(lahf), + + /* 0xa0 */ + op2(mov, AL, Ob), + op2(mov, AX, Ov), + op2(mov, Ob, AL), + op2(mov, Ov, AX), + op0(movsb), + op0(movsw), + op0(cmpsb), + op0(cmpsw), + op2(test, AL, Ib), + op2(test, AX, Iz), + op1(stosb, AL), + op1(stosw, AX), + op1(lodsb, AL), + op1(lodsw, AX), + op1(scasb, AL), + op1(scasw, AX), + + /* 0xb0 */ + op2(mov, AL, Ib), + op2(mov, CL, Ib), + op2(mov, DL, Ib), + op2(mov, BL, Ib), + op2(mov, AH, Ib), + op2(mov, CH, Ib), + op2(mov, DH, Ib), + op2(mov, BH, Ib), +#define _(r) op2(mov, r, Iv), + foreach_x86_gp_reg +#undef _ + + /* 0xc0 */ + op2f(modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, Ib), + op2f(modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, Ib), + op1(ret, Iw), + op0(ret), + op2(les, Gz, Mp), + op2(lds, Gz, Mp), + op2f(modrm_group_11, X86_INSN_FLAG_MODRM_REG_GROUP_11, Eb, Ib), + op2f(modrm_group_11, X86_INSN_FLAG_MODRM_REG_GROUP_11, Ev, Iz), + op2(enter, Iw, Ib), + op0(leave), + op1(ret, Iw), + op0(ret), + op0(int3), + op1(int, Ib), + op0(into), + op0(iret), + + /* 0xd0 */ + op2f(modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, 1b), + op2f(modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, 1b), + op2f(modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, CL), + op2f(modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, CL), + op0(aam), + op0(aad), + op0(salc), + op0(xlat), + /* FIXME x87 */ + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + + /* 0xe0 */ + op1(loopnz, Jb), + op1(loopz, Jb), + op1(loop, Jb), + op1(jcxz, Jb), + op2(in, AL, Ib), + op2(in, AX, Ib), + op2(out, Ib, AL), + op2(out, Ib, AX), + op1f(call, X86_INSN_SPEC_DEFAULT_64_BIT, Jz), + op1f(jmp, X86_INSN_SPEC_DEFAULT_64_BIT, Jz), + op1(jmp, Ap), + op1(jmp, Jb), + op2(in, AL, DX), + op2(in, AX, DX), + op2(out, DX, AL), + op2(out, DX, AX), + + /* 0xf0 */ + op0(lock), + op0(int1), + op0(repne), + op0(rep), + op0(hlt), + op0(cmc), + op0f(modrm_group_3, X86_INSN_FLAG_MODRM_REG_GROUP_3), + op0f(modrm_group_3, X86_INSN_FLAG_MODRM_REG_GROUP_3), + op0(clc), + op0(stc), + op0(cli), + op0(sti), + op0(cld), + op0(std), + op1f(modrm_group_4, X86_INSN_FLAG_MODRM_REG_GROUP_4, Eb), + op0f(modrm_group_5, X86_INSN_FLAG_MODRM_REG_GROUP_5), +}; + +// clang-format on \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_sse_group.c b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_sse_group.c new file mode 100644 index 0000000..8e56a9b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_sse_group.c @@ -0,0 +1,545 @@ +static x86_insn_group8_t x86_insn_sse_groups_repz[] = { + [X86_INSN_SSE_GROUP_10].insns = + { + op2(movss, Gx, Ex), + op2(movss, Ex, Gx), + op2(movsldup, Gx, Ex), + op0(bad), + op0(bad), + op0(bad), + op2(movshdup, Gx, Ex), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_28].insns = + { + op0(bad), + op0(bad), + op2(cvtsi2ss, Gx, Ev), + op0(bad), + op2(cvttss2si, Gv, Ex), + op2(cvtss2si, Gv, Ex), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_50].insns = + { + op0(bad), + op2(sqrtss, Gx, Ex), + op2(rsqrtps, Gx, Ex), + op2(rcpss, Gx, Ex), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_58].insns = + { + op2(addss, Gx, Ex), + op2(mulss, Gx, Ex), + op2(cvtss2sd, Gx, Ex), + op2(cvttps2dq, Gx, Ex), + op2(subss, Gx, Ex), + op2(minss, Gx, Ex), + op2(divss, Gx, Ex), + op2(maxss, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_60].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_68].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(movdqu, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_70].insns = + { + op3(pshufhw, Gx, Ex, Ib), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_78].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(movq, Gx, Ex), + op2(movdqu, Ex, Gx), + }, + + [X86_INSN_SSE_GROUP_c0].insns = + { + op0(bad), + op0(bad), + op3(cmpss, Gx, Ex, Ib), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_d0].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(movq2dq, Gx, Em), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_d8].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_e0].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(cvtdq2pd, Gx, Ex), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_e8].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_f0].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_f8].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, +}; + +static x86_insn_group8_t x86_insn_sse_groups_operand_size[] = { + [X86_INSN_SSE_GROUP_10].insns = + { + op2(movupd, Gx, Ex), + op2(movupd, Ex, Gx), + op2(movlpd, Gx, Ex), + op2(movlpd, Ex, Gx), + op2(unpcklpd, Gx, Ex), + op2(unpckhpd, Gx, Ex), + op2(movhpd, Gx, Mx), + op2(movhpd, Mx, Gx), + }, + + [X86_INSN_SSE_GROUP_28].insns = + { + op2(movapd, Gx, Ex), + op2(movapd, Ex, Gx), + op2(cvtpi2pd, Gx, Ex), + op2(movntpd, Mx, Gx), + op2(cvttpd2pi, Gx, Mx), + op2(cvtpd2pi, Gx, Mx), + op2(ucomisd, Gx, Ex), + op2(comisd, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_50].insns = + { + op2(movmskpd, Gd, Rx), + op2(sqrtpd, Gx, Ex), + op0(bad), + op0(bad), + op2(andpd, Gx, Ex), + op2(andnpd, Gx, Ex), + op2(orpd, Gx, Ex), + op2(xorpd, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_58].insns = + { + op2(addpd, Gx, Ex), + op2(mulpd, Gx, Ex), + op2(cvtpd2ps, Gx, Ex), + op2(cvtps2dq, Gx, Ex), + op2(subpd, Gx, Ex), + op2(minpd, Gx, Ex), + op2(divpd, Gx, Ex), + op2(maxpd, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_60].insns = + { + op2(punpcklbw, Gx, Ex), + op2(punpcklwd, Gx, Ex), + op2(punpckldq, Gx, Ex), + op2(packsswb, Gx, Ex), + op2(pcmpgtb, Gx, Ex), + op2(pcmpgtw, Gx, Ex), + op2(pcmpgtd, Gx, Ex), + op2(packuswb, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_68].insns = + { + op2(punpckhbw, Gx, Ex), + op2(punpckhwd, Gx, Ex), + op2(punpckhdq, Gx, Ex), + op2(packssdw, Gx, Ex), + op2(punpcklqdq, Gx, Ex), + op2(punpckhqdq, Gx, Ex), + op2(movd, Gx, Ev), + op2(movdqa, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_70].insns = + { + op3(pshufd, Gx, Ex, Ib), + op0f(modrm_group_12, X86_INSN_FLAG_MODRM_REG_GROUP_12), + op0f(modrm_group_13, X86_INSN_FLAG_MODRM_REG_GROUP_13), + op0f(modrm_group_14, X86_INSN_FLAG_MODRM_REG_GROUP_14), + op2(pcmpeqb, Gx, Ex), + op2(pcmpeqw, Gx, Ex), + op2(pcmpeqd, Gx, Ex), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_78].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(haddpd, Gx, Ex), + op2(hsubpd, Gx, Ex), + op2(movd, Ev, Gx), + op2(movdqa, Ex, Gx), + }, + + [X86_INSN_SSE_GROUP_c0].insns = + { + op0(bad), + op0(bad), + op3(cmppd, Gx, Ex, Ib), + op0(bad), + op3(pinsrw, Gx, Ew, Ib), + op3(pextrw, Gd, Gx, Ib), + op3(shufpd, Gx, Ex, Ib), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_d0].insns = + { + op2(addsubpd, Gx, Ex), + op2(psrlw, Gx, Ex), + op2(psrld, Gx, Ex), + op2(psrlq, Gx, Ex), + op2(paddq, Gx, Ex), + op2(pmullw, Gx, Ex), + op2(movq, Ex, Gx), + op2(pmovmskb, Gd, Rx), + }, + + [X86_INSN_SSE_GROUP_d8].insns = + { + op2(psubusb, Gx, Ex), + op2(psubusw, Gx, Ex), + op2(pminub, Gx, Ex), + op2(pand, Gx, Ex), + op2(paddusb, Gx, Ex), + op2(paddusw, Gx, Ex), + op2(pmaxub, Gx, Ex), + op2(pandn, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_e0].insns = + { + op2(pavgb, Gx, Ex), + op2(psraw, Gx, Ex), + op2(psrad, Gx, Ex), + op2(pavgw, Gx, Ex), + op2(pmulhuw, Gx, Ex), + op2(pmulhw, Gx, Ex), + op2(cvttpd2dq, Gx, Ex), + op2(movntdq, Mx, Gx), + }, + + [X86_INSN_SSE_GROUP_e8].insns = + { + op2(psubsb, Gx, Ex), + op2(psubsw, Gx, Ex), + op2(pminsw, Gx, Ex), + op2(por, Gx, Ex), + op2(paddsb, Gx, Ex), + op2(paddsw, Gx, Ex), + op2(pmaxsw, Gx, Ex), + op2(pxor, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_f0].insns = + { + op0(bad), + op2(psllw, Gx, Ex), + op2(pslld, Gx, Ex), + op2(psllq, Gx, Ex), + op2(pmuludq, Gx, Ex), + op2(pmaddwd, Gx, Ex), + op2(psadbw, Gx, Ex), + op2(maskmovdqu, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_f8].insns = + { + op2(psubb, Gx, Ex), + op2(psubw, Gx, Ex), + op2(psubd, Gx, Ex), + op2(psubq, Gx, Ex), + op2(paddb, Gx, Ex), + op2(paddw, Gx, Ex), + op2(paddd, Gx, Ex), + op0(bad), + }, +}; + +static x86_insn_group8_t x86_insn_sse_groups_repnz[] = { + [X86_INSN_SSE_GROUP_10].insns = + { + op2(movsd, Gx, Ex), + op2(movsd, Ex, Gx), + op2(movddup, Gx, Ex), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_28].insns = + { + op0(bad), + op0(bad), + op2(cvtsi2sd, Gx, Ev), + op0(bad), + op2(cvttsd2si, Gv, Ex), + op2(cvtsd2si, Gv, Ex), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_50].insns = + { + op0(bad), + op2(sqrtsd, Gx, Ex), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_58].insns = + { + op2(addsd, Gx, Ex), + op2(mulsd, Gx, Ex), + op2(cvtsd2ss, Gx, Ex), + op0(bad), + op2(subsd, Gx, Ex), + op2(minsd, Gx, Ex), + op2(divsd, Gx, Ex), + op2(maxsd, Gx, Ex), + }, + + [X86_INSN_SSE_GROUP_60].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_68].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_70].insns = + { + op3(pshuflw, Gx, Ex, Ib), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_78].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(haddps, Gx, Ex), + op2(hsubps, Gx, Ex), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_c0].insns = + { + op0(bad), + op0(bad), + op3(cmpsd, Gx, Ex, Ib), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_d0].insns = + { + op2(addsubps, Gx, Ex), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(movdq2q, Gm, Ex), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_d8].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_e0].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2(cvtpd2dq, Gx, Ex), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_e8].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_f0].insns = + { + op2(lddqu, Gx, Mx), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, + + [X86_INSN_SSE_GROUP_f8].insns = + { + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + }, +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_two_byte.c b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_two_byte.c new file mode 100644 index 0000000..900d0b3 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InstructionRelocation/x86/x86_insn_decode/x86_opcode_two_byte.c @@ -0,0 +1,249 @@ + +// clang-format off +static x86_insn_spec_t x86_opcode_map_two_byte[256] = { + /* 0x00 */ + op0f(modrm_group_6, X86_INSN_FLAG_MODRM_REG_GROUP_6), + op0f(modrm_group_7, X86_INSN_FLAG_MODRM_REG_GROUP_7), + op2(lar, Gv, Ew), + op2(lsl, Gv, Ew), + op0(bad), + op0(syscall), + op0(clts), + op0(sysret), + op0(invd), + op0(wbinvd), + op0(bad), + op0(ud2), + op0(bad), + op0f(modrm_group_p, X86_INSN_FLAG_MODRM_REG_GROUP_p), + op0(femms), + op0(escape_3dnow), + + /* 0x10 */ + op2f(movups, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), + op2f(movups, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), + op2f(movlps, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), + op2f(movlps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), + op2f(unpcklps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), + op2f(unpckhps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), + op2f(movhps, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), + op2f(movhps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), + op0f(modrm_group_16, X86_INSN_FLAG_MODRM_REG_GROUP_16), + op0(nop), + op0(nop), + op0(nop), + op0(nop), + op0(nop), + op0(nop), + op0(nop), + + /* 0x20 */ + op2(mov, Rv, Cv), + op2(mov, Rv, Dv), + op2(mov, Cv, Rv), + op2(mov, Dv, Rv), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op2f(movaps, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), + op2f(movaps, X86_INSN_FLAG_SSE_GROUP_28, Ex, Gx), + op2f(cvtpi2ps, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), + op2f(movntps, X86_INSN_FLAG_SSE_GROUP_28, Mx, Gx), + op2f(cvttps2pi, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), + op2f(cvtps2pi, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), + op2f(ucomiss, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), + op2f(comiss, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), + + /* 0x30 */ + op0(wrmsr), + op0(rdtsc), + op0(rdmsr), + op0(rdpmc), + op0(sysenter), + op0(sysexit), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + op0(bad), + +/* 0x40 */ +#define _(x) op2(cmov##x, Gv, Ev), + foreach_x86_condition +#undef _ + + /* 0x50 */ + op2f(movmskps, X86_INSN_FLAG_SSE_GROUP_50, Gd, Rx), + op2f(sqrtps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), + op2f(rsqrtps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), + op2f(rcpps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), + op2f(andps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), + op2f(andnps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), + op2f(orps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), + op2f(xorps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), + op2f(addps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), + op2f(mulps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), + op2f(cvtps2pd, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), + op2f(cvtdq2ps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), + op2f(subps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), + op2f(minps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), + op2f(divps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), + op2f(maxps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), + + /* 0x60 */ + op2f(punpcklbw, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), + op2f(punpcklwd, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), + op2f(punpckldq, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), + op2f(packsswb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), + op2f(pcmpgtb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), + op2f(pcmpgtw, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), + op2f(pcmpgtd, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), + op2f(packuswb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), + op2f(punpckhbw, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), + op2f(punpckhwd, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), + op2f(punpckhdq, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), + op2f(packssdw, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_68), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_68), + op2f(movd, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), + op2f(movq, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), + + /* 0x70 */ + op3f(pshufw, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em, Ib), + op0f(modrm_group_12, X86_INSN_FLAG_MODRM_REG_GROUP_12), + op0f(modrm_group_13, X86_INSN_FLAG_MODRM_REG_GROUP_13), + op0f(modrm_group_14, X86_INSN_FLAG_MODRM_REG_GROUP_14), + op2f(pcmpeqb, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), + op2f(pcmpeqw, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), + op2f(pcmpeqd, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), + op0f(emms, X86_INSN_FLAG_SSE_GROUP_70), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_78), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_78), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_78), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_78), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_78), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_78), + op2f(movd, X86_INSN_FLAG_SSE_GROUP_78, Em, Gm), + op2f(movq, X86_INSN_FLAG_SSE_GROUP_78, Em, Gm), + +/* 0x80 */ +#define _(x) op1(jmp##x, Jz), + foreach_x86_condition +#undef _ + +/* 0x90 */ +#define _(x) op1(set##x, Eb), + foreach_x86_condition +#undef _ + + /* 0xa0 */ + op0(push_fs), + op0(pop_fs), + op0(cpuid), + op2(bt, Ev, Gv), + op3(shld, Ev, Gv, Ib), + op3(shld, Ev, Gv, CL), + op0(bad), + op0(bad), + op0(push_gs), + op0(pop_gs), + op0(rsm), + op2(bts, Ev, Gv), + op3(shrd, Ev, Gv, Ib), + op3(shrd, Ev, Gv, CL), + op0f(modrm_group_15, X86_INSN_FLAG_MODRM_REG_GROUP_15), + op2(imul, Gv, Ev), + + /* 0xb0 */ + op2(cmpxchg, Eb, Gb), + op2(cmpxchg, Ev, Gv), + op2(lss, Gz, Mp), + op2(btr, Ev, Gv), + op2(lfs, Gz, Mp), + op2(lgs, Gz, Mp), + op2(movzbl, Gv, Eb), + op2(movzwl, Gv, Ew), + op0(bad), + op0f(modrm_group_10, X86_INSN_FLAG_MODRM_REG_GROUP_10), + op2f(modrm_group_8, X86_INSN_FLAG_MODRM_REG_GROUP_8, Ev, Ib), + op2(btc, Ev, Gv), + op2(bsf, Gv, Ev), + op2(bsr, Gv, Ev), + op2(movsx, Gv, Eb), + op2(movsx, Gv, Ew), + + /* 0xc0 */ + op2(xadd, Eb, Gb), + op2(xadd, Ev, Gv), + op3f(cmpps, X86_INSN_FLAG_SSE_GROUP_c0, Gx, Ex, Ib), + op2(movnti, Mv, Gv), + op3f(pinsrw, X86_INSN_FLAG_SSE_GROUP_c0, Gm, Ew, Ib), + op3f(pextrw, X86_INSN_FLAG_SSE_GROUP_c0, Gd, Rm, Ib), + op3f(shufps, X86_INSN_FLAG_SSE_GROUP_c0, Gx, Ex, Ib), + op1f(modrm_group_9, X86_INSN_FLAG_MODRM_REG_GROUP_9, Mx), +#define _(r) op1(bswap, r), + foreach_x86_gp_reg +#undef _ + + /* 0xd0 */ + op0f(bad, X86_INSN_FLAG_SSE_GROUP_d0), + op2f(psrlw, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), + op2f(psrld, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), + op2f(psrlq, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), + op2f(paddq, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), + op2f(pmullw, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_d0), + op2f(pmovmskb, X86_INSN_FLAG_SSE_GROUP_d0, Gd, Rm), + op2f(psubusb, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), + op2f(psubusw, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), + op2f(pminub, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), + op2f(pand, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), + op2f(paddusb, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), + op2f(paddusw, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), + op2f(pmaxub, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), + op2f(pandn, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), + + /* 0xe0 */ + op2f(pavgb, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), + op2f(psraw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), + op2f(psrad, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), + op2f(pavgw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), + op2f(pmulhuw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), + op2f(pmulhw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), + op2f(bad, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), + op2f(movntq, X86_INSN_FLAG_SSE_GROUP_e0, Mm, Gm), + op2f(psubsb, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), + op2f(psubsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), + op2f(pminsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), + op2f(por, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), + op2f(paddsb, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), + op2f(paddsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), + op2f(pmaxsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), + op2f(pxor, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), + + /* 0xf0 */ + op0f(bad, X86_INSN_FLAG_SSE_GROUP_f0), + op2f(psllw, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), + op2f(pslld, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), + op2f(psllq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), + op2f(pmuludq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), + op2f(pmaddwd, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), + op2f(psadbw, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), + op2f(maskmovq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), + op2f(psubb, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), + op2f(psubw, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), + op2f(psubd, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), + op2f(psubq, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), + op2f(paddb, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), + op2f(paddw, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), + op2f(paddd, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), + op0f(bad, X86_INSN_FLAG_SSE_GROUP_f8), +}; + +// clang-format on \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InterceptEntry.cpp b/app/src/main/cpp/Dobby/source/InterceptEntry.cpp new file mode 100644 index 0000000..cf7184b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptEntry.cpp @@ -0,0 +1,18 @@ +#include "InterceptEntry.h" +#include "Interceptor.h" + +InterceptEntry::InterceptEntry(InterceptEntryType type, addr_t address) { + this->type = type; + +#if defined(TARGET_ARCH_ARM) + if (address % 2) { + address -= 1; + this->thumb_mode = true; + } else { + this->thumb_mode = false; + } +#endif + + this->patched_addr = address; + this->id = Interceptor::SharedInstance()->count(); +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InterceptEntry.h b/app/src/main/cpp/Dobby/source/InterceptEntry.h new file mode 100644 index 0000000..0fff858 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptEntry.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include "common_header.h" + +typedef enum { kFunctionInlineHook, kInstructionInstrument } InterceptEntryType; + +class InterceptRouting; + +typedef struct InterceptEntry { + uint32_t id; + InterceptEntryType type; + InterceptRouting *routing; + + union { + addr_t addr; + addr_t patched_addr; + }; + uint32_t patched_size; + + addr_t relocated_addr; + uint32_t relocated_size; + + uint8_t origin_insns[256]; + uint32_t origin_insn_size; + + bool thumb_mode; + + InterceptEntry(InterceptEntryType type, addr_t address); +} InterceptEntry; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/InterceptRouting.cpp b/app/src/main/cpp/Dobby/source/InterceptRouting/InterceptRouting.cpp new file mode 100644 index 0000000..b2e7b6d --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/InterceptRouting.cpp @@ -0,0 +1,98 @@ +#include "dobby_internal.h" + +#include "InterceptRouting/InterceptRouting.h" +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +using namespace zz; + +void log_hex_format(uint8_t *buffer, uint32_t buffer_size) { + char output[1024] = {0}; + for (int i = 0; i < buffer_size && i < sizeof(output); i++) { + snprintf(output + strlen(output), 3, "%02x ", *((uint8_t *)buffer + i)); + } + DLOG(0, "%s", output); +}; + +void InterceptRouting::Prepare() { +} + +// generate relocated code +bool InterceptRouting::GenerateRelocatedCode() { + uint32_t tramp_size = GetTrampolineBuffer()->GetBufferSize(); + origin_ = new CodeMemBlock(entry_->patched_addr, tramp_size); + relocated_ = new CodeMemBlock(); + + auto buffer = (void *)entry_->patched_addr; +#if defined(TARGET_ARCH_ARM) + if (entry_->thumb_mode) { + buffer = (void *)((addr_t)buffer + 1); + } +#endif + GenRelocateCodeAndBranch(buffer, origin_, relocated_); + if (relocated_->size == 0) { + ERROR_LOG("[insn relocate]] failed"); + return false; + } + + // set the relocated instruction address + entry_->relocated_addr = relocated_->addr; + + // save original prologue + memcpy((void *)entry_->origin_insns, (void *)origin_->addr, origin_->size); + entry_->origin_insn_size = origin_->size; + + // log + DLOG(0, "[insn relocate] origin %p - %d", origin_->addr, origin_->size); + log_hex_format((uint8_t *)origin_->addr, origin_->size); + + DLOG(0, "[insn relocate] relocated %p - %d", relocated_->addr, relocated_->size); + log_hex_format((uint8_t *)relocated_->addr, relocated_->size); + + return true; +} + +bool InterceptRouting::GenerateTrampolineBuffer(addr_t src, addr_t dst) { + // if near branch trampoline plugin enabled + if (RoutingPluginManager::near_branch_trampoline) { + auto plugin = static_cast(RoutingPluginManager::near_branch_trampoline); + if (plugin->GenerateTrampolineBuffer(this, src, dst) == false) { + DLOG(0, "Failed enable near branch trampoline plugin"); + } + } + + if (GetTrampolineBuffer() == nullptr) { + auto tramp_buffer = GenerateNormalTrampolineBuffer(src, dst); + SetTrampolineBuffer(tramp_buffer); + } + return true; +} + +// active routing, patch origin instructions as trampoline +void InterceptRouting::Active() { + MemoryOperationError err; + err = DobbyCodePatch((void *)entry_->patched_addr, trampoline_buffer_->GetBuffer(), + trampoline_buffer_->GetBufferSize()); + if (err != kMemoryOperationSuccess) { + ERROR_LOG("[intercept routing] active failed"); + return; + } + DLOG(0, "[intercept routing] active"); +} + +void InterceptRouting::Commit() { + this->Active(); +} + +#if 0 +int InterceptRouting::PredefinedTrampolineSize() { +#if __arm64__ + return 12; +#elif __arm__ + return 8; +#endif +} +#endif + +InterceptEntry *InterceptRouting::GetInterceptEntry() { + return entry_; +}; diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/InterceptRouting.h b/app/src/main/cpp/Dobby/source/InterceptRouting/InterceptRouting.h new file mode 100644 index 0000000..e21ca32 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/InterceptRouting.h @@ -0,0 +1,62 @@ +#pragma once + +#include "InterceptEntry.h" +#include "MemoryAllocator/AssemblyCodeBuilder.h" +#include "InstructionRelocation/InstructionRelocation.h" +#include "TrampolineBridge/Trampoline/Trampoline.h" + +class InterceptRouting { +public: + explicit InterceptRouting(InterceptEntry *entry) : entry_(entry) { + entry->routing = this; + + origin_ = nullptr; + relocated_ = nullptr; + + trampoline_ = nullptr; + trampoline_buffer_ = nullptr; + trampoline_target_ = 0; + } + + virtual void DispatchRouting() = 0; + + virtual void Prepare(); + + virtual void Active(); + + void Commit(); + + InterceptEntry *GetInterceptEntry(); + + void SetTrampolineBuffer(CodeBufferBase *buffer) { + trampoline_buffer_ = buffer; + } + + CodeBufferBase *GetTrampolineBuffer() { + return trampoline_buffer_; + } + + void SetTrampolineTarget(addr_t address) { + trampoline_target_ = address; + } + + addr_t GetTrampolineTarget() { + return trampoline_target_; + } + +protected: + bool GenerateRelocatedCode(); + + bool GenerateTrampolineBuffer(addr_t src, addr_t dst); + +protected: + InterceptEntry *entry_; + + CodeMemBlock *origin_; + CodeMemBlock *relocated_; + + CodeMemBlock *trampoline_; + // trampoline buffer before active + CodeBufferBase *trampoline_buffer_; + addr_t trampoline_target_; +}; diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHook.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHook.cc new file mode 100644 index 0000000..e85fb92 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHook.cc @@ -0,0 +1,51 @@ +#include "dobby_internal.h" + +#include "Interceptor.h" +#include "InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHookRouting.h" + +PUBLIC int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func) { + if (!address) { + ERROR_LOG("function address is 0x0"); + return RS_FAILED; + } + +#if defined(__APPLE__) && defined(__arm64__) +#if __has_feature(ptrauth_calls) + address = ptrauth_strip(address, ptrauth_key_asia); + replace_func = ptrauth_strip(replace_func, ptrauth_key_asia); +#endif +#endif + +#if defined(ANDROID) + void *page_align_address = (void *)ALIGN_FLOOR(address, OSMemory::PageSize()); + if (!OSMemory::SetPermission(page_align_address, OSMemory::PageSize(), kReadExecute)) { + return RS_FAILED; + } +#endif + + DLOG(0, "----- [DobbyHook:%p] -----", address); + + // check if already register + auto entry = Interceptor::SharedInstance()->find((addr_t)address); + if (entry) { + ERROR_LOG("%p already been hooked.", address); + return RS_FAILED; + } + + entry = new InterceptEntry(kFunctionInlineHook, (addr_t)address); + + auto *routing = new FunctionInlineHookRouting(entry, replace_func); + routing->Prepare(); + routing->DispatchRouting(); + + // set origin func entry with as relocated instructions + if (origin_func) { + *origin_func = (dobby_dummy_func_t)entry->relocated_addr; + } + + routing->Commit(); + + Interceptor::SharedInstance()->add(entry); + + return RS_SUCCESS; +} diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHookRouting.h b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHookRouting.h new file mode 100644 index 0000000..d308ace --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHookRouting.h @@ -0,0 +1,22 @@ +#pragma once + +#include "dobby_internal.h" + +#include "InterceptRouting/InterceptRouting.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +class FunctionInlineHookRouting : public InterceptRouting { +public: + FunctionInlineHookRouting(InterceptEntry *entry, dobby_dummy_func_t replace_func) : InterceptRouting(entry) { + this->replace_func = replace_func; + } + + void DispatchRouting() override; + +private: + void BuildRouting(); + +private: + dobby_dummy_func_t replace_func; +}; diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/RoutingImpl.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/RoutingImpl.cc new file mode 100644 index 0000000..015c946 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionInlineHook/RoutingImpl.cc @@ -0,0 +1,22 @@ +#include "dobby_internal.h" +#include "InterceptRouting/Routing/FunctionInlineHook/FunctionInlineHookRouting.h" + +void FunctionInlineHookRouting::BuildRouting() { + SetTrampolineTarget((addr_t)replace_func); + + // generate trampoline buffer, run before GenerateRelocatedCode + addr_t from = entry_->patched_addr; +#if defined(TARGET_ARCH_ARM) + if (entry_->thumb_mode) + from += 1; +#endif + addr_t to = GetTrampolineTarget(); + GenerateTrampolineBuffer(from, to); +} + +void FunctionInlineHookRouting::DispatchRouting() { + BuildRouting(); + + // generate relocated code which size == trampoline size + GenerateRelocatedCode(); +} diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/FunctionWrapperExport.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/FunctionWrapperExport.cc new file mode 100644 index 0000000..18a6645 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/FunctionWrapperExport.cc @@ -0,0 +1,27 @@ +#include "dobby_internal.h" + +#include "logging/logging.h" + +#include "Interceptor.h" +#include "InterceptRouting/InterceptRouting.h" + +#include "function-wrapper.h" + +PUBLIC int DobbyWrap(void *function_address, PreCallTy pre_call, PostCallTy post_call) { + DLOG(0, "Initialize 'DobbyWrap' hook at %p", function_address); + + Interceptor *interceptor = Interceptor::SharedInstance(); + + InterceptEntry *entry = new InterceptEntry(); + entry->id = interceptor->entries->getCount(); + entry->type = kFunctionWrapper; + entry->function_address = function_address; + + FunctionWrapperRouting *routing = new FunctionWrapperRouting(entry); + routing->DispatchRouting(); + interceptor->addHookEntry(entry); + routing->Commit(); + + DLOG(0, "Finalize %p", function_address); + return RS_SUCCESS; +} diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/function-wrapper.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/function-wrapper.cc new file mode 100644 index 0000000..354beeb --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/function-wrapper.cc @@ -0,0 +1,38 @@ +#include "dobby_internal.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +#include "intercept_routing_handler.h" + +#include "function-wrapper.h" + +void FunctionWrapperRouting::DispatchRouting() { + Prepare(); + BuildPreCallRouting(); + BuildPostCallRouting(); +} + +// Add pre_call(prologue) handler before running the origin function, +void FunctionWrapperRouting::BuildPreCallRouting() { + // create closure trampoline jump to prologue_routing_dispath with the `entry_` data + ClosureTrampolineEntry *cte = ClosureTrampoline::CreateClosureTrampoline(entry_, (void *)prologue_routing_dispatch); + this->prologue_dispatch_bridge = cte->address; + + DLOG(0, "Create pre call closure trampoline to 'prologue_routing_dispatch' at %p", cte->address); +} + +// Add post_call(epilogue) handler before `Return` of the origin function, as implementation is replace the origin +// `Return Address` of the function. +void FunctionWrapperRouting::BuildPostCallRouting() { + // create closure trampoline jump to prologue_routing_dispath with the `entry_` data + ClosureTrampolineEntry *closure_trampoline_entry; + // format trampoline + closure_trampoline_entry = ClosureTrampoline::CreateClosureTrampoline(entry_, (void *)epilogue_routing_dispatch); + DLOG(0, "Create post call closure trampoline to 'prologue_routing_dispatch' at %p", + closure_trampoline_entry->address); + + this->SetTrampolineTarget(closure_trampoline_entry->address); + this->epilogue_dispatch_bridge = closure_trampoline_entry->address; + + GenerateTrampolineBuffer(entry_->target_address, GetTrampolineTarget()); +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/function-wrapper.h b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/function-wrapper.h new file mode 100644 index 0000000..38903ef --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/function-wrapper.h @@ -0,0 +1,40 @@ +#ifndef FUNCTION_WRAPPER_H +#define FUNCTION_WRAPPER_H + +#include "dobby_internal.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" +#include "InterceptRouting/InterceptRouting.h" +#include "Interceptor.h" + +#if TARGET_ARCH_IA32 +#elif TARGET_ARCH_X64 +#include "InterceptRouting/x64/X64InterceptRouting.h" +#elif TARGET_ARCH_ARM64 +#include "InterceptRouting/arm64/ARM64InterceptRouting.h" +#elif TARGET_ARCH_ARM +#else +#error "unsupported architecture" +#endif + +class FunctionWrapperRouting : public InterceptRouting { +public: + FunctionWrapperRouting(InterceptEntry *entry) : InterceptRouting(entry) { + } + + void DispatchRouting(); + + void *GetTrampolineTarget(); + +private: + void BuildPreCallRouting(); + + void BuildPostCallRouting(); + +private: + void *prologue_dispatch_bridge; + + void *epilogue_dispatch_bridge; +}; + +#endif diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/intercept_routing_handler.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/intercept_routing_handler.cc new file mode 100644 index 0000000..85dbd12 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/intercept_routing_handler.cc @@ -0,0 +1,79 @@ + +#include "dobby_internal.h" + +#include "logging/logging.h" + +#include "intercept_routing_handler.h" + +#include "function-wrapper.h" +#include "intercept_routing_handler.h" + +#include "MultiThreadSupport/ThreadSupport.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h" + +void pre_call_forward_handler(DobbyRegisterContext *ctx, InterceptEntry *entry) { + FunctionWrapperRouting *routing = (FunctionWrapperRouting *)entry->routing; + + StackFrame *stackframe = new StackFrame(); + // create stack frame as common variable between pre_call and post_call + ThreadSupport::PushStackFrame(stackframe); + + // run the `pre_call` before execute origin function which has been relocated(fixed) + if (routing->pre_call) { + PreCallTy pre_call; + InterceptEntry entry; + entry.hook_id = entry->id; + entry.target_address = entry->target_address; + pre_call = routing->pre_call; + // run the pre_call with the power of accessing all registers + (*pre_call)(ctx, (const InterceptEntry *)&entry); + } + + // save the origin ret address, and use in `post_call_forword_handler` + stackframe->orig_ret = get_func_ret_address(ctx); + + // set the prologue bridge next hop address with the patched instructions has been relocated + set_routing_bridge_next_hop(ctx, entry->relocated_origin_function); + + // replace the function ret address with our epilogue_routing_dispatch + set_func_ret_address(ctx, entry->epilogue_dispatch_bridge); +} + +void post_call_forward_handler(DobbyRegisterContext *ctx, InterceptEntry *entry) { + FunctionWrapperRouting *routing = (FunctionWrapperRouting *)entry->routing; + + // pop stack frame as common variable between pre_call and post_call + StackFrame *stackframe = ThreadSupport::PopStackFrame(); + + // run the `post_call`, and access all the register value, as the origin function done, + if (routing->post_call) { + PostCallTy post_call; + InterceptEntry entry; + entry.hook_id = entry->id; + entry.target_address = entry->target_address; + post_call = routing->post_call; + + // run the post_call with the power of accessing all registers + (*post_call)(ctx, (const InterceptEntry *)&entry); + } + + // set epilogue bridge next hop address with origin ret address, restore the call. + set_routing_bridge_next_hop(ctx, stackframe->orig_ret); +} + +// run the user handler **before run the origin-instructions(which have been relocated)** +void prologue_routing_dispatch(DobbyRegisterContext *ctx, ClosureTrampolineEntry *closure_trampoline_entry) { + DLOG(0, "Catch prologue dispatch"); + InterceptEntry *entry = static_cast(closure_trampoline_entry->carry_data); + pre_call_forward_handler(ctx, entry); + return; +} + +// run the user handler **before the function return** by replace the lr register +void epilogue_routing_dispatch(DobbyRegisterContext *ctx, ClosureTrampolineEntry *closure_trampoline_entry) { + DLOG(0, "Catch epilogue dispatch"); + InterceptEntry *entry = static_cast(closure_trampoline_entry->carry_data); + post_call_forward_handler(ctx, entry); + return; +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/intercept_routing_handler.h b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/intercept_routing_handler.h new file mode 100644 index 0000000..a7cbc48 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/FunctionWrapper/intercept_routing_handler.h @@ -0,0 +1,27 @@ +#ifndef FUNCTION_WRAPPER_INTERCEPT_ROUTING_HANDLER_H +#define FUNCTION_WRAPPER_INTERCEPT_ROUTING_HANDLER_H + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" +#include "Interceptor.h" +#include "dobby_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +// Dispatch the routing befor running the origin function +void prologue_routing_dispatch(DobbyRegisterContext *ctx, ClosureTrampolineEntry *entry); + +// Dispatch the routing before the function return . (as it's implementation by relpace `return address` in the stack +// ,or LR register) +void epilogue_routing_dispatch(DobbyRegisterContext *ctx, ClosureTrampolineEntry *entry); + +void pre_call_forward_handler(DobbyRegisterContext *ctx, InterceptEntry *entry); + +void post_call_forward_handler(DobbyRegisterContext *ctx, InterceptEntry *entry); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/InstructionInstrument.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/InstructionInstrument.cc new file mode 100644 index 0000000..d96ed84 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/InstructionInstrument.cc @@ -0,0 +1,44 @@ +#include "dobby_internal.h" + +#include "Interceptor.h" +#include "InterceptRouting/InterceptRouting.h" +#include "InterceptRouting/Routing/InstructionInstrument/InstructionInstrumentRouting.h" + +PUBLIC int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler) { + if (!address) { + ERROR_LOG("address is 0x0.\n"); + return RS_FAILED; + } + +#if defined(__APPLE__) && defined(__arm64__) +#if __has_feature(ptrauth_calls) + address = ptrauth_strip(address, ptrauth_key_asia); +#endif +#endif + +#if defined(ANDROID) + void *page_align_address = (void *)ALIGN_FLOOR(address, OSMemory::PageSize()); + if (!OSMemory::SetPermission(page_align_address, OSMemory::PageSize(), kReadExecute)) { + return RS_FAILED; + } +#endif + + DLOG(0, "\n\n----- [DobbyInstrument:%p] -----", address); + + auto entry = Interceptor::SharedInstance()->find((addr_t)address); + if (entry) { + ERROR_LOG("%s already been instrumented.", address); + return RS_FAILED; + } + + entry = new InterceptEntry(kInstructionInstrument, (addr_t)address); + + auto routing = new InstructionInstrumentRouting(entry, pre_handler, nullptr); + routing->Prepare(); + routing->DispatchRouting(); + routing->Commit(); + + Interceptor::SharedInstance()->add(entry); + + return RS_SUCCESS; +} diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/InstructionInstrumentRouting.h b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/InstructionInstrumentRouting.h new file mode 100644 index 0000000..e4eed62 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/InstructionInstrumentRouting.h @@ -0,0 +1,30 @@ +#pragma once + +#include "dobby_internal.h" + +#include "InterceptRouting/InterceptRouting.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +class InstructionInstrumentRouting : public InterceptRouting { +public: + InstructionInstrumentRouting(InterceptEntry *entry, dobby_instrument_callback_t pre_handler, + dobby_instrument_callback_t post_handler) + : InterceptRouting(entry) { + this->prologue_dispatch_bridge = nullptr; + this->pre_handler = pre_handler; + this->post_handler = post_handler; + } + + void DispatchRouting() override; + +private: + void BuildRouting(); + +public: + dobby_instrument_callback_t pre_handler; + dobby_instrument_callback_t post_handler; + +private: + void *prologue_dispatch_bridge; +}; diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/RoutingImpl.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/RoutingImpl.cc new file mode 100644 index 0000000..1631431 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/RoutingImpl.cc @@ -0,0 +1,42 @@ + +#include "dobby_internal.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +#include "InterceptRouting/Routing/InstructionInstrument/InstructionInstrumentRouting.h" +#include "InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.h" + +// create closure trampoline jump to prologue_routing_dispatch with the `entry_` data +void InstructionInstrumentRouting::BuildRouting() { + void *handler = (void *)instrument_routing_dispatch; +#if defined(__APPLE__) && defined(__arm64__) +#if __has_feature(ptrauth_calls) + handler = ptrauth_strip(handler, ptrauth_key_asia); +#endif +#endif + auto closure_trampoline = ClosureTrampoline::CreateClosureTrampoline(entry_, handler); + this->SetTrampolineTarget((addr_t)closure_trampoline->address); + DLOG(0, "[closure trampoline] closure trampoline: %p, data: %p", closure_trampoline->address, entry_); + + // generate trampoline buffer, before `GenerateRelocatedCode` + addr_t from = entry_->patched_addr; +#if defined(TARGET_ARCH_ARM) + if (entry_->thumb_mode) + from += 1; +#endif + addr_t to = GetTrampolineTarget(); + GenerateTrampolineBuffer(from, to); +} + +void InstructionInstrumentRouting::DispatchRouting() { + BuildRouting(); + + // generate relocated code which size == trampoline size + GenerateRelocatedCode(); +} + +#if 0 +void *InstructionInstrumentRouting::GetTrampolineTarget() { + return this->prologue_dispatch_bridge; +} +#endif diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.cc new file mode 100644 index 0000000..baaa0cf --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.cc @@ -0,0 +1,21 @@ +#include "dobby_internal.h" + +#include "InterceptRouting/Routing/InstructionInstrument/InstructionInstrumentRouting.h" +#include "InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h" + +void instrument_forward_handler(InterceptEntry *entry, DobbyRegisterContext *ctx) { + auto routing = static_cast(entry->routing); + if (routing->pre_handler) { + auto handler = (dobby_instrument_callback_t)routing->pre_handler; + (*handler)((void *)entry->patched_addr, ctx); + } + + // set prologue bridge next hop address as relocated instructions + set_routing_bridge_next_hop(ctx, (void *)entry->relocated_addr); +} + +void instrument_routing_dispatch(InterceptEntry *entry, DobbyRegisterContext *ctx) { + instrument_forward_handler(entry, ctx); +} diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.h b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.h new file mode 100644 index 0000000..553f1eb --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/Routing/InstructionInstrument/instrument_routing_handler.h @@ -0,0 +1,7 @@ +#pragma once + +#include "dobby_internal.h" + +extern "C" { +void instrument_routing_dispatch(InterceptEntry *entry, DobbyRegisterContext *ctx); +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/NearBranchTrampoline.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/NearBranchTrampoline.cc new file mode 100644 index 0000000..951a8ec --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/NearBranchTrampoline.cc @@ -0,0 +1,47 @@ +#include "InterceptRouting/RoutingPlugin/NearBranchTrampoline/NearBranchTrampoline.h" + +#include "dobby_internal.h" + +#include "MemoryAllocator/NearMemoryAllocator.h" + +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +using namespace zz; + +PUBLIC void dobby_enable_near_branch_trampoline() { + RoutingPluginInterface *plugin = new NearBranchTrampolinePlugin; + RoutingPluginManager::registerPlugin("near_branch_trampoline", plugin); + RoutingPluginManager::near_branch_trampoline = plugin; +} + +PUBLIC void dobby_disable_near_branch_trampoline() { + NearBranchTrampolinePlugin *plugin = (NearBranchTrampolinePlugin *)RoutingPluginManager::near_branch_trampoline; + delete plugin; + RoutingPluginManager::near_branch_trampoline = NULL; +} + +#if 0 +int NearBranchTrampolinePlugin::PredefinedTrampolineSize() { +#if __arm64__ + return 4; +#elif __arm__ + return 4; +#endif +} +#endif + +extern CodeBufferBase *GenerateNearTrampolineBuffer(InterceptRouting *routing, addr_t from, addr_t to); +bool NearBranchTrampolinePlugin::GenerateTrampolineBuffer(InterceptRouting *routing, addr_t src, addr_t dst) { + CodeBufferBase *trampoline_buffer; + trampoline_buffer = GenerateNearTrampolineBuffer(routing, src, dst); + if (trampoline_buffer == NULL) + return false; + routing->SetTrampolineBuffer(trampoline_buffer); + return true; +} + +// generate trampoline, patch the original entry +bool NearBranchTrampolinePlugin::Active(InterceptRouting *routing) { + InterceptEntry *entry = routing->GetInterceptEntry(); + return true; +} diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/NearBranchTrampoline.h b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/NearBranchTrampoline.h new file mode 100644 index 0000000..8b8a948 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/NearBranchTrampoline.h @@ -0,0 +1,15 @@ +#pragma once + +#include "dobby_internal.h" + +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +class NearBranchTrampolinePlugin : public RoutingPluginInterface { + bool Prepare(InterceptRouting *routing) { + return false; + }; + + bool Active(InterceptRouting *routing); + + bool GenerateTrampolineBuffer(InterceptRouting *routing, addr_t src, addr_t dst); +}; diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/near_trampoline_arm64.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/near_trampoline_arm64.cc new file mode 100644 index 0000000..f168889 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/NearBranchTrampoline/near_trampoline_arm64.cc @@ -0,0 +1,82 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM64) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-arm64.h" +#include "core/codegen/codegen-arm64.h" + +#include "MemoryAllocator/NearMemoryAllocator.h" +#include "InstructionRelocation/arm64/InstructionRelocationARM64.h" +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +using namespace zz::arm64; + +#define ARM64_B_XXX_RANGE ((1 << 25) << 2) // signed + +// If BranchType is B_Branch and the branch_range of `B` is not enough +// build the transfer to forward the b branch +static AssemblyCode *GenerateFastForwardTrampoline(addr_t src, addr_t dst) { + TurboAssembler turbo_assembler_(nullptr); +#define _ turbo_assembler_. + + // [adrp + add + br branch] + auto tramp_size = 3 *4; + auto tramp_mem = NearMemoryAllocator::SharedAllocator()->allocateNearExecMemory(tramp_size, src, ARM64_B_XXX_RANGE); + if (tramp_mem == nullptr) { + ERROR_LOG("search near code block failed"); + return nullptr; + } + + // Use adrp + add branch + uint64_t distance = llabs((int64_t)(tramp_mem - dst)); + uint64_t adrp_range = ((uint64_t)1 << (2 + 19 + 12 - 1)); + if (distance < adrp_range) { + // use adrp + add + br branch == (3 * 4) trampoline size + _ AdrpAdd(TMP_REG_0, (uint64_t)tramp_mem, dst); + _ br(TMP_REG_0); + DLOG(0, "forward trampoline use [adrp, add, br]"); + } else { + // use mov + br == (4 * 5) trampoline size + _ Mov(TMP_REG_0, dst); + _ br(TMP_REG_0); + DLOG(0, "forward trampoline use [mov, br]"); + + auto tramp_size = turbo_assembler_.GetCodeBuffer()->GetBufferSize(); + tramp_mem = + NearMemoryAllocator::SharedAllocator()->allocateNearExecMemory(tramp_size, src, ARM64_B_XXX_RANGE); + if (tramp_mem == nullptr) { + ERROR_LOG("Can't found near code chunk"); + return nullptr; + } + } + + turbo_assembler_.SetRealizedAddress((void *)tramp_mem); + + AssemblyCode *code = nullptr; + code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + return code; +} + +CodeBufferBase *GenerateNearTrampolineBuffer(InterceptRouting *routing, addr_t src, addr_t dst) { + CodeBufferBase *result = nullptr; + + TurboAssembler turbo_assembler_((void *)src); +#define _ turbo_assembler_. + + // branch to trampoline_target directly + if (llabs((long long)dst - (long long)src) < ARM64_B_XXX_RANGE) { + _ b(dst - src); + } else { + auto fast_forward_trampoline = GenerateFastForwardTrampoline(src, dst); + if (!fast_forward_trampoline) + return nullptr; + _ b(fast_forward_trampoline->addr - src); + } + + // free the original trampoline + result = turbo_assembler_.GetCodeBuffer()->Copy(); + return result; +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/RoutingPlugin.cc b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/RoutingPlugin.cc new file mode 100644 index 0000000..f945e4e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/RoutingPlugin.cc @@ -0,0 +1,11 @@ +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +std::vector RoutingPluginManager::plugins; + +RoutingPluginInterface *RoutingPluginManager::near_branch_trampoline = NULL; + +void RoutingPluginManager::registerPlugin(const char *name, RoutingPluginInterface *plugin) { + DLOG(0, "register %s plugin", name); + + RoutingPluginManager::plugins.push_back(plugin); +} diff --git a/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/RoutingPlugin.h b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/RoutingPlugin.h new file mode 100644 index 0000000..a692c22 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/InterceptRouting/RoutingPlugin/RoutingPlugin.h @@ -0,0 +1,30 @@ +#pragma once + +#include "dobby_internal.h" + +#include "InterceptRouting/InterceptRouting.h" + +class RoutingPluginInterface { +public: + // @Return: if false will continue to iter next plugin + virtual bool Prepare(InterceptRouting *routing) = 0; + + // @Return: if false will continue to iter next plugin + virtual bool Active(InterceptRouting *routing) = 0; + + // @Return: if false will continue to iter next plugin + virtual bool GenerateTrampolineBuffer(InterceptRouting *routing, addr_t src, addr_t dst) = 0; + +private: + char name_[256]; +}; + +class RoutingPluginManager { +public: + static void registerPlugin(const char *name, RoutingPluginInterface *plugin); + +public: + static std::vector plugins; + + static RoutingPluginInterface *near_branch_trampoline; +}; diff --git a/app/src/main/cpp/Dobby/source/Interceptor.cpp b/app/src/main/cpp/Dobby/source/Interceptor.cpp new file mode 100644 index 0000000..7cfe113 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Interceptor.cpp @@ -0,0 +1,40 @@ +#include "Interceptor.h" + +Interceptor *Interceptor::instance = nullptr; + +Interceptor *Interceptor::SharedInstance() { + if (Interceptor::instance == nullptr) { + Interceptor::instance = new Interceptor(); + } + return Interceptor::instance; +} + +InterceptEntry *Interceptor::find(addr_t addr) { + for (auto *entry : entries) { + if (entry->patched_addr == addr) { + return entry; + } + } + return nullptr; +} + +void Interceptor::add(InterceptEntry *entry) { + entries.push_back(entry); +} + +void Interceptor::remove(addr_t addr) { + for (auto iter = entries.begin(); iter != entries.end(); iter++) { + if ((*iter)->patched_addr == addr) { + entries.erase(iter); + break; + } + } +} + +const InterceptEntry *Interceptor::getEntry(int i) { + return entries[i]; +} + +int Interceptor::count() { + return entries.size(); +} diff --git a/app/src/main/cpp/Dobby/source/Interceptor.h b/app/src/main/cpp/Dobby/source/Interceptor.h new file mode 100644 index 0000000..0fa0c3d --- /dev/null +++ b/app/src/main/cpp/Dobby/source/Interceptor.h @@ -0,0 +1,25 @@ +#pragma once + +#include "dobby_internal.h" +#include "InterceptEntry.h" + +class Interceptor { +public: + static Interceptor *SharedInstance(); + +public: + InterceptEntry *find(addr_t addr); + + void remove(addr_t addr); + + void add(InterceptEntry *entry); + + const InterceptEntry *getEntry(int i); + + int count(); + +private: + static Interceptor *instance; + + tinystl::vector entries; +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/AssemblyCodeBuilder.cc b/app/src/main/cpp/Dobby/source/MemoryAllocator/AssemblyCodeBuilder.cc new file mode 100644 index 0000000..774411a --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/AssemblyCodeBuilder.cc @@ -0,0 +1,34 @@ +#include "MemoryAllocator/AssemblyCodeBuilder.h" + +#include "dobby_internal.h" +#include "PlatformUnifiedInterface/ExecMemory/CodePatchTool.h" + +AssemblyCode *AssemblyCodeBuilder::FinalizeFromTurboAssembler(AssemblerBase *assembler) { + auto buffer = (CodeBufferBase *)assembler->GetCodeBuffer(); + auto realized_addr = (addr_t)assembler->GetRealizedAddress(); +#if defined(TEST_WITH_UNICORN) + // impl: unicorn emulator map memory + realized_addr = 0; +#endif + if (!realized_addr) { + size_t buffer_size = 0; + buffer_size = buffer->GetBufferSize(); +#if TARGET_ARCH_ARM + // extra bytes for align needed + buffer_size += 4; +#endif + + auto block = MemoryAllocator::SharedAllocator()->allocateExecBlock(buffer_size); + if (block == nullptr) + return nullptr; + + realized_addr = block->addr; + assembler->SetRealizedAddress((void *)realized_addr); + } + + // Realize the buffer code to the executable memory address, remove the external label, etc + DobbyCodePatch((void *)realized_addr, buffer->GetBuffer(), buffer->GetBufferSize()); + + auto block = new AssemblyCode(realized_addr, buffer->GetBufferSize()); + return block; +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/AssemblyCodeBuilder.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/AssemblyCodeBuilder.h new file mode 100644 index 0000000..d704c56 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/AssemblyCodeBuilder.h @@ -0,0 +1,14 @@ +#pragma once + +#include "PlatformUnifiedInterface/MemoryAllocator.h" + +#include "core/assembler/assembler.h" + +using namespace zz; + +using AssemblyCode = CodeMemBlock; + +class AssemblyCodeBuilder { +public: + static AssemblyCode *FinalizeFromTurboAssembler(AssemblerBase *assembler); +}; diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/CodeBufferBase.cc b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/CodeBufferBase.cc new file mode 100644 index 0000000..eab9622 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/CodeBufferBase.cc @@ -0,0 +1,53 @@ +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +CodeBufferBase *CodeBufferBase::Copy() { + CodeBufferBase *result = new CodeBufferBase(); + result->EmitBuffer(GetBuffer(), GetBufferSize()); + return result; +} + +void CodeBufferBase::Emit8(uint8_t data) { + Emit(data); +} + +void CodeBufferBase::Emit16(uint16_t data) { + Emit(data); +} + +void CodeBufferBase::Emit32(uint32_t data) { + Emit(data); +} + +void CodeBufferBase::Emit64(uint64_t data) { + Emit(data); +} + +void CodeBufferBase::EmitBuffer(uint8_t *buffer, int buffer_size) { + buffer_.insert(buffer_.end(), buffer, buffer + buffer_size); +} + +uint8_t *CodeBufferBase::GetBuffer() { + return buffer_.data(); +} + +size_t CodeBufferBase::GetBufferSize() { + return buffer_.size(); +} + +#if 0 // Template Advanced won't enable even in userspace +template T CodeBufferBase::Load(int offset) { + return *reinterpret_cast(buffer + offset); +} + +template void CodeBufferBase::Store(int offset, T value) { + *reinterpret_cast(buffer + offset) = value; +} + +template void CodeBufferBase::Emit(T value) { + // Ensure the free space enough for the template T value + ensureCapacity(sizeof(T) + GetBufferSize()); + + *reinterpret_cast(buffer_cursor) = value; + buffer_cursor += sizeof(T); +} +#endif diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/CodeBufferBase.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/CodeBufferBase.h new file mode 100644 index 0000000..8a2dc0c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/CodeBufferBase.h @@ -0,0 +1,40 @@ +#pragma once + +#include "common_header.h" + +class CodeBufferBase { +public: + CodeBufferBase() { + } + +public: + virtual CodeBufferBase *Copy(); + + void Emit8(uint8_t data); + + void Emit16(uint16_t data); + + void Emit32(uint32_t data); + + void Emit64(uint64_t data); + + template T Load(int offset) { + return *(T *)(buffer_.data() + offset); + } + + template void Store(int offset, T value) { + *(T *)(buffer_.data() + offset) = value; + } + + template void Emit(T value) { + EmitBuffer((uint8_t *)&value, sizeof(value)); + } + + void EmitBuffer(uint8_t *buffer, int len); + + uint8_t *GetBuffer(); + size_t GetBufferSize(); + +private: + tinystl::vector buffer_; +}; diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-arm.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-arm.h new file mode 100644 index 0000000..0255947 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-arm.h @@ -0,0 +1,59 @@ +#ifndef CODE_BUFFER_ARM_H +#define CODE_BUFFER_ARM_H + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +typedef int32_t arm_inst_t; +typedef int16_t thumb1_inst_t; +typedef int32_t thumb2_inst_t; + +class CodeBuffer : public CodeBufferBase { + enum ExecuteState { ARMExecuteState, ThumbExecuteState }; + +public: + CodeBuffer() : CodeBufferBase() { + } + +public: + arm_inst_t LoadARMInst(uint32_t offset) { + return *reinterpret_cast(GetBuffer() + offset); + } + + thumb1_inst_t LoadThumb1Inst(uint32_t offset) { + return *reinterpret_cast(GetBuffer() + offset); + } + + thumb2_inst_t LoadThumb2Inst(uint32_t offset) { + return *reinterpret_cast(GetBuffer() + offset); + } + + void RewriteAddr(uint32_t offset, addr32_t addr) { + memcpy(GetBuffer() + offset, &addr, sizeof(addr)); + } + + void RewriteARMInst(uint32_t offset, arm_inst_t instr) { + *reinterpret_cast(GetBuffer() + offset) = instr; + } + + void RewriteThumb1Inst(uint32_t offset, thumb1_inst_t instr) { + *reinterpret_cast(GetBuffer() + offset) = instr; + } + + void RewriteThumb2Inst(uint32_t offset, thumb2_inst_t instr) { + memcpy(GetBuffer() + offset, &instr, sizeof(instr)); + } + + void EmitARMInst(arm_inst_t instr) { + Emit(instr); + } + + void EmitThumb1Inst(thumb1_inst_t instr) { + Emit(instr); + } + + void EmitThumb2Inst(thumb2_inst_t instr) { + Emit(instr); + } +}; + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-arm64.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-arm64.h new file mode 100644 index 0000000..266e10b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-arm64.h @@ -0,0 +1,24 @@ +#ifndef CODE_BUFFER_ARM64_H +#define CODE_BUFFER_ARM64_H + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +typedef int32_t arm64_inst_t; + +class CodeBuffer : public CodeBufferBase { + +public: + CodeBuffer() : CodeBufferBase() { + } + +public: + arm64_inst_t LoadInst(uint32_t offset) { + return *reinterpret_cast(GetBuffer() + offset); + } + + void RewriteInst(uint32_t offset, arm64_inst_t instr) { + *reinterpret_cast(GetBuffer() + offset) = instr; + } +}; + +#endif diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x64.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x64.h new file mode 100644 index 0000000..913ee8a --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x64.h @@ -0,0 +1,17 @@ +#ifndef CODE_BUFFER_X64_H +#define CODE_BUFFER_X64_H + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +class CodeBuffer : public CodeBufferBase { +public: + CodeBuffer() : CodeBufferBase() { + } + +public: + void FixBindLabel(int offset, int32_t disp) { + Store(offset, disp); + } +}; + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x86.cc b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x86.cc new file mode 100644 index 0000000..827eca0 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x86.cc @@ -0,0 +1,18 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) + +#include "MemoryAllocator/CodeBuffer/code-buffer-x86.h" + +void CodeBuffer::Emit32(int32_t data) { + ensureCapacity(GetBufferSize() + sizeof(int32_t)); + *reinterpret_cast(getCursor()) = data; + buffer_cursor += sizeof(int32_t); + return; +} + +void CodeBuffer::FixBindLabel(int offset, int32_t disp) { + *reinterpret_cast(buffer + offset) = disp; + return; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x86.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x86.h new file mode 100644 index 0000000..a66d29e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code-buffer-x86.h @@ -0,0 +1,11 @@ +#pragma once + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +class CodeBuffer : public CodeBufferBase { +public: + CodeBuffer() : CodeBufferBase() { + } +public: + void FixBindLabel(int offset, int32_t disp); +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_arm.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_arm.h new file mode 100644 index 0000000..0fe8346 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_arm.h @@ -0,0 +1,56 @@ +#pragma once + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +typedef int32_t arm_inst_t; +typedef int16_t thumb1_inst_t; +typedef int32_t thumb2_inst_t; + +class CodeBuffer : public CodeBufferBase { + enum ExecuteState { ARMExecuteState, ThumbExecuteState }; + +public: + CodeBuffer() : CodeBufferBase() { + } + +public: + arm_inst_t LoadARMInst(uint32_t offset) { + return *reinterpret_cast(GetBuffer() + offset); + } + + thumb1_inst_t LoadThumb1Inst(uint32_t offset) { + return *reinterpret_cast(GetBuffer() + offset); + } + + thumb2_inst_t LoadThumb2Inst(uint32_t offset) { + return *reinterpret_cast(GetBuffer() + offset); + } + + void RewriteAddr(uint32_t offset, addr32_t addr) { + memcpy(GetBuffer() + offset, &addr, sizeof(addr)); + } + + void RewriteARMInst(uint32_t offset, arm_inst_t instr) { + *reinterpret_cast(GetBuffer() + offset) = instr; + } + + void RewriteThumb1Inst(uint32_t offset, thumb1_inst_t instr) { + *reinterpret_cast(GetBuffer() + offset) = instr; + } + + void RewriteThumb2Inst(uint32_t offset, thumb2_inst_t instr) { + memcpy(GetBuffer() + offset, &instr, sizeof(instr)); + } + + void EmitARMInst(arm_inst_t instr) { + Emit(instr); + } + + void EmitThumb1Inst(thumb1_inst_t instr) { + Emit(instr); + } + + void EmitThumb2Inst(thumb2_inst_t instr) { + Emit(instr); + } +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_arm64.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_arm64.h new file mode 100644 index 0000000..4c8d803 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_arm64.h @@ -0,0 +1,21 @@ +#pragma once + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +typedef int32_t arm64_inst_t; + +class CodeBuffer : public CodeBufferBase { + +public: + CodeBuffer() : CodeBufferBase() { + } + +public: + arm64_inst_t LoadInst(uint32_t offset) { + return *reinterpret_cast(GetBuffer() + offset); + } + + void RewriteInst(uint32_t offset, arm64_inst_t instr) { + *reinterpret_cast(GetBuffer() + offset) = instr; + } +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_x64.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_x64.h new file mode 100644 index 0000000..d80dfb8 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_x64.h @@ -0,0 +1,14 @@ +#pragma once + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +class CodeBuffer : public CodeBufferBase { +public: + CodeBuffer() : CodeBufferBase() { + } + +public: + void FixBindLabel(int offset, int32_t disp) { + Store(offset, disp); + } +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_x86.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_x86.h new file mode 100644 index 0000000..c75bc2d --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/CodeBuffer/code_buffer_x86.h @@ -0,0 +1,13 @@ +#pragma once + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +class CodeBuffer : public CodeBufferBase { +public: + CodeBuffer() : CodeBufferBase() { + } +public: + void FixBindLabel(int offset, int32_t disp) { + Store(offset, disp); + } +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/MemoryAllocator.cc b/app/src/main/cpp/Dobby/source/MemoryAllocator/MemoryAllocator.cc new file mode 100644 index 0000000..a4b865c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/MemoryAllocator.cc @@ -0,0 +1,106 @@ +#include "dobby_internal.h" + +#include "PlatformUnifiedInterface/MemoryAllocator.h" + +MemBlock *MemoryArena::allocMemBlock(size_t size) { + // insufficient memory + if (this->end - this->cursor_addr < size) { + return nullptr; + } + + auto result = new MemBlock(cursor_addr, size); + cursor_addr += size; + return result; +} + +MemoryAllocator *MemoryAllocator::shared_allocator = nullptr; +MemoryAllocator *MemoryAllocator::SharedAllocator() { + if (MemoryAllocator::shared_allocator == nullptr) { + MemoryAllocator::shared_allocator = new MemoryAllocator(); + } + return MemoryAllocator::shared_allocator; +} + +CodeMemoryArena *MemoryAllocator::allocateCodeMemoryArena(uint32_t size) { + CHECK_EQ(size % OSMemory::PageSize(), 0); + uint32_t arena_size = size; + auto arena_addr = OSMemory::Allocate(arena_size, kNoAccess); + OSMemory::SetPermission(arena_addr, arena_size, kReadExecute); + + auto result = new CodeMemoryArena((addr_t)arena_addr, (size_t)arena_size); + code_arenas.push_back(result); + return result; +} + +CodeMemBlock *MemoryAllocator::allocateExecBlock(uint32_t size) { + CodeMemBlock *block = nullptr; + for (auto iter = code_arenas.begin(); iter != code_arenas.end(); iter++) { + auto arena = static_cast(*iter); + block = arena->allocMemBlock(size); + if (block) + break; + } + if (!block) { + // allocate new arena + auto arena_size = ALIGN_CEIL(size, OSMemory::PageSize()); + auto arena = allocateCodeMemoryArena(arena_size); + block = arena->allocMemBlock(size); + CHECK_NOT_NULL(block); + } + + DLOG(0, "[memory allocator] allocate exec memory at: %p, size: %p", block->addr, block->size); + return block; +} + +uint8_t *MemoryAllocator::allocateExecMemory(uint32_t size) { + auto block = allocateExecBlock(size); + return (uint8_t *)block->addr; +} +uint8_t *MemoryAllocator::allocateExecMemory(uint8_t *buffer, uint32_t buffer_size) { + auto mem = allocateExecMemory(buffer_size); + auto ret = DobbyCodePatch(mem, buffer, buffer_size); + CHECK_EQ(ret, kMemoryOperationSuccess); + return mem; +} + +DataMemoryArena *MemoryAllocator::allocateDataMemoryArena(uint32_t size) { + DataMemoryArena *result = nullptr; + + uint32_t buffer_size = ALIGN_CEIL(size, OSMemory::PageSize()); + void *buffer = OSMemory::Allocate(buffer_size, kNoAccess); + OSMemory::SetPermission(buffer, buffer_size, kReadWrite); + + result = new DataMemoryArena((addr_t)buffer, (size_t)buffer_size); + data_arenas.push_back(result); + return result; +} + +DataMemBlock *MemoryAllocator::allocateDataBlock(uint32_t size) { + CodeMemBlock *block = nullptr; + for (auto iter = data_arenas.begin(); iter != data_arenas.end(); iter++) { + auto arena = static_cast(*iter); + block = arena->allocMemBlock(size); + if (block) + break; + } + if (!block) { + // allocate new arena + auto arena = allocateCodeMemoryArena(size); + block = arena->allocMemBlock(size); + CHECK_NOT_NULL(block); + } + + DLOG(0, "[memory allocator] allocate data memory at: %p, size: %p", block->addr, block->size); + return block; +} + +uint8_t *MemoryAllocator::allocateDataMemory(uint32_t size) { + auto block = allocateDataBlock(size); + return (uint8_t *)block->addr; +} + +uint8_t *MemoryAllocator::allocateDataMemory(uint8_t *buffer, uint32_t buffer_size) { + auto mem = allocateDataMemory(buffer_size); + memcpy(mem, buffer, buffer_size); + return mem; +} diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/NearMemoryAllocator.cc b/app/src/main/cpp/Dobby/source/MemoryAllocator/NearMemoryAllocator.cc new file mode 100644 index 0000000..800f740 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/NearMemoryAllocator.cc @@ -0,0 +1,234 @@ +#include "NearMemoryAllocator.h" + +#include "dobby_internal.h" + +#include "PlatformUtil/ProcessRuntimeUtility.h" + +using namespace zz; + +#define KB (1024uLL) +#define MB (1024uLL * KB) +#define GB (1024uLL * MB) + +#if defined(WIN32) +static const void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { + if (!haystack || !needle) { + return haystack; + } else { + const char *h = (const char *)haystack; + const char *n = (const char *)needle; + size_t l = needlelen; + const char *r = h; + while (l && (l <= haystacklen)) { + if (*n++ != *h++) { + r = h; + n = (const char *)needle; + l = needlelen; + } else { + --l; + } + --haystacklen; + } + return l ? nullptr : r; + } +} +#endif + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +NearMemoryAllocator *NearMemoryAllocator::shared_allocator = nullptr; +NearMemoryAllocator *NearMemoryAllocator::SharedAllocator() { + if (NearMemoryAllocator::shared_allocator == nullptr) { + NearMemoryAllocator::shared_allocator = new NearMemoryAllocator(); + } + return NearMemoryAllocator::shared_allocator; +} + +MemBlock *NearMemoryAllocator::allocateNearBlockFromDefaultAllocator(uint32_t size, addr_t pos, size_t search_range, + bool executable) { + addr_t min_valid_addr, max_valid_addr; + min_valid_addr = pos - search_range; + max_valid_addr = pos + search_range; + + auto allocateFromDefaultArena = [&](MemoryArena *arena, uint32_t size) -> addr_t { + addr_t unused_mem_start = arena->cursor_addr; + addr_t unused_mem_end = arena->addr + arena->size; + + // check if unused region total out of search range + if (unused_mem_end < min_valid_addr || unused_mem_start > max_valid_addr) + return 0; + + unused_mem_start = max(unused_mem_start, min_valid_addr); + unused_mem_end = min(unused_mem_end, max_valid_addr); + + // check if invalid + if(unused_mem_start >= unused_mem_end) + return 0; + + + // check if has sufficient memory + if (unused_mem_end - unused_mem_start < size) + return 0; + + DLOG(0, "[near memory allocator] unused memory from default allocator %p(%p), within pos: %p, serach_range: %p", unused_mem_start, size, pos, search_range); + return unused_mem_start; + }; + + MemoryArena *arena = nullptr; + addr_t unused_mem = 0; + if (executable) { + for (auto iter = default_allocator->code_arenas.begin(); iter != default_allocator->code_arenas.end(); iter++) { + arena = *iter; + unused_mem = allocateFromDefaultArena(arena, size); + if (!unused_mem) + continue; + + break; + } + } else { + for (auto iter = default_allocator->data_arenas.begin(); iter != default_allocator->data_arenas.end(); iter++) { + arena = *iter; + unused_mem = allocateFromDefaultArena(arena, size); + if (unused_mem) + continue; + } + } + + if (!unused_mem) + return nullptr; + + // skip placeholder block + // FIXME: allocate the placeholder but mark it as freed + auto placeholder_block_size = unused_mem - arena->cursor_addr; + arena->allocMemBlock(placeholder_block_size); + + + auto block = arena->allocMemBlock(size); + return block; +} + +MemBlock *NearMemoryAllocator::allocateNearBlockFromUnusedRegion(uint32_t size, addr_t pos, size_t search_range, + bool executable) { + + addr_t min_valid_addr, max_valid_addr; + min_valid_addr = pos - search_range; + max_valid_addr = pos + search_range; + + auto check_has_sufficient_memory_between_region = [&](MemRegion region, MemRegion next_region, uint32_t size) -> addr_t { + addr_t unused_mem_start = region.start + region.size; + addr_t unused_mem_end = next_region.start; + + // check if unused region total out of search range + if (unused_mem_end < min_valid_addr || unused_mem_start > max_valid_addr) + return 0; + + // align + unused_mem_start = ALIGN_FLOOR(unused_mem_start, 4); + + unused_mem_start = max(unused_mem_start, min_valid_addr); + unused_mem_end = min(unused_mem_end, max_valid_addr); + + // check if invalid + if (unused_mem_start >= unused_mem_end) + return 0; + + // check if has sufficient memory + if (unused_mem_end - unused_mem_start < size) + return 0; + + DLOG(0, "[near memory allocator] unused memory from unused region %p(%p), within pos: %p, serach_range: %p", unused_mem_start, size, pos, search_range); + return unused_mem_start; + }; + + addr_t unused_mem = 0; + auto regions = ProcessRuntimeUtility::GetProcessMemoryLayout(); + for (size_t i = 0; i + 1 < regions.size(); i++) { + unused_mem = check_has_sufficient_memory_between_region(regions[i], regions[i + 1], size); + if (unused_mem == 0) + continue; + break; + } + + if (!unused_mem) + return nullptr; + + auto unused_arena_first_page_addr = (addr_t)ALIGN_FLOOR(unused_mem, OSMemory::PageSize()); + auto unused_arena_end_page_addr = ALIGN_FLOOR(unused_mem + size, OSMemory::PageSize()); + auto unused_arena_size = unused_arena_end_page_addr - unused_arena_first_page_addr + OSMemory::PageSize(); + auto unused_arena_addr = unused_arena_first_page_addr; + + if (OSMemory::Allocate(unused_arena_size, kNoAccess, (void *)unused_arena_addr) == nullptr) { + ERROR_LOG("[near memory allocator] allocate fixed page failed %p", unused_arena_addr); + return nullptr; + } + + auto register_near_arena = [&](addr_t arena_addr, size_t arena_size) -> MemoryArena * { + MemoryArena *arena = nullptr; + if (executable) { + arena = new CodeMemoryArena(arena_addr, arena_size); + default_allocator->code_arenas.push_back(arena); + } else { + arena = new DataMemoryArena(arena_addr, arena_size); + default_allocator->data_arenas.push_back(arena); + } + OSMemory::SetPermission((void *)arena->addr, arena->size, executable ? kReadExecute : kReadWrite); + return arena; + }; + + auto unused_arena = register_near_arena(unused_arena_addr, unused_arena_size); + + // skip placeholder block + // FIXME: allocate the placeholder but mark it as freed + auto placeholder_block_size = unused_mem - unused_arena->cursor_addr; + unused_arena->allocMemBlock(placeholder_block_size); + + auto block = unused_arena->allocMemBlock(size); + return block; +} + +MemBlock *NearMemoryAllocator::allocateNearBlock(uint32_t size, addr_t pos, size_t search_range, bool executable) { + MemBlock *result = nullptr; + result = allocateNearBlockFromDefaultAllocator(size, pos, search_range, executable); + if (!result) { + result = allocateNearBlockFromUnusedRegion(size, pos, search_range, executable); + } + + if (!result) { + ERROR_LOG("[near memory allocator] allocate near block failed (%p, %p, %p)", size, pos, search_range); + } + return result; +} + +uint8_t *NearMemoryAllocator::allocateNearExecMemory(uint32_t size, addr_t pos, size_t search_range) { + auto block = allocateNearBlock(size, pos, search_range, true); + if (!block) + return nullptr; + + DLOG(0, "[near memory allocator] allocate exec memory at: %p, size: %p", block->addr, block->size); + return (uint8_t *)block->addr; +} + +uint8_t *NearMemoryAllocator::allocateNearExecMemory(uint8_t *buffer, uint32_t buffer_size, addr_t pos, + size_t search_range) { + auto mem = allocateNearExecMemory(buffer_size, pos, search_range); + auto ret = DobbyCodePatch(mem, buffer, buffer_size); + CHECK_EQ(ret, kMemoryOperationSuccess); + return mem; +} + +uint8_t *NearMemoryAllocator::allocateNearDataMemory(uint32_t size, addr_t pos, size_t search_range) { + auto block = allocateNearBlock(size, pos, search_range, false); + if (!block) + return nullptr; + + DLOG(0, "[near memory allocator] allocate data memory at: %p, size: %p", block->addr, block->size); + return (uint8_t *)block->addr; +} + +uint8_t *NearMemoryAllocator::allocateNearDataMemory(uint8_t *buffer, uint32_t buffer_size, addr_t pos, + size_t search_range) { + auto mem = allocateNearExecMemory(buffer_size, pos, search_range); + memcpy(mem, buffer, buffer_size); + return mem; +} diff --git a/app/src/main/cpp/Dobby/source/MemoryAllocator/NearMemoryAllocator.h b/app/src/main/cpp/Dobby/source/MemoryAllocator/NearMemoryAllocator.h new file mode 100644 index 0000000..a1e39bc --- /dev/null +++ b/app/src/main/cpp/Dobby/source/MemoryAllocator/NearMemoryAllocator.h @@ -0,0 +1,30 @@ +#pragma once + +#include "PlatformUnifiedInterface/MemoryAllocator.h" + +#include "common_header.h" + +class NearMemoryAllocator { +public: + MemoryAllocator *default_allocator; + NearMemoryAllocator() { + default_allocator = MemoryAllocator::SharedAllocator(); + } + +private: + static NearMemoryAllocator *shared_allocator; + +public: + static NearMemoryAllocator *SharedAllocator(); + +public: + MemBlock *allocateNearBlock(uint32_t size, addr_t pos, size_t search_range, bool executable); + MemBlock *allocateNearBlockFromDefaultAllocator(uint32_t size, addr_t pos, size_t search_range, bool executable); + MemBlock *allocateNearBlockFromUnusedRegion(uint32_t size, addr_t pos, size_t search_range, bool executable); + + uint8_t *allocateNearExecMemory(uint32_t size, addr_t pos, size_t search_range); + uint8_t *allocateNearExecMemory(uint8_t *buffer, uint32_t buffer_size, addr_t pos, size_t search_range); + + uint8_t *allocateNearDataMemory(uint32_t size, addr_t pos, size_t search_range); + uint8_t *allocateNearDataMemory(uint8_t *buffer, uint32_t buffer_size, addr_t pos, size_t search_range); +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/ExecMemory/ClearCacheTool.h b/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/ExecMemory/ClearCacheTool.h new file mode 100644 index 0000000..ee407cb --- /dev/null +++ b/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/ExecMemory/ClearCacheTool.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void ClearCache(void *start, void *end); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/ExecMemory/CodePatchTool.h b/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/ExecMemory/CodePatchTool.h new file mode 100644 index 0000000..f6c1073 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/ExecMemory/CodePatchTool.h @@ -0,0 +1,3 @@ +#pragma once + +MemoryOperationError DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size); \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/MemoryAllocator.h b/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/MemoryAllocator.h new file mode 100644 index 0000000..b4b928c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/PlatformUnifiedInterface/MemoryAllocator.h @@ -0,0 +1,101 @@ +#pragma once + +#include "common_header.h" + +struct MemRange { + addr_t start; + addr_t end; + size_t size; + + MemRange(addr_t start, size_t size) : start(start), end(0), size(size) { + end = start + size; + } + + void reset(addr_t start, size_t size) { + this->start = start; + this->size = size; + end = start + size; + } +}; + +struct MemBlock : MemRange { + addr_t addr; + + MemBlock() : MemRange(0, 0), addr(0) { + } + + MemBlock(addr_t addr, size_t size) : MemRange(addr, size), addr(addr) { + } + + void reset(addr_t addr, size_t size) { + MemRange::reset(addr, size); + this->addr = addr; + } +}; + +struct MemoryArena : MemRange { + addr_t addr; + addr_t cursor_addr; + + std::vector memory_blocks; + + MemoryArena(addr_t addr, size_t size) : MemRange(addr, size), addr(addr), cursor_addr(addr) { + } + + virtual MemBlock *allocMemBlock(size_t size); +}; + +using CodeMemBlock = MemBlock; +using CodeMemoryArena = MemoryArena; + +#if 0 +struct CodeMemoryArena : MemoryArena { + CodeMemoryArena(addr_t addr, size_t size) : MemoryArena(addr, size) { + } + + CodeMemBlock *allocateCodeMemBlock(size_t size) { + return allocMemBlock(size); + } +}; +#endif + +using DataMemBlock = MemBlock; +using DataMemoryArena = MemoryArena; + +#if 0 +struct DataMemoryArena : MemoryArena { +public: + DataMemoryArena(addr_t addr, size_t size) : MemoryArena(addr, size) { + } + + DataMemBlock *allocateDataMemBlock(size_t size) { + return allocMemBlock(size); + } +}; +#endif + +class NearMemoryAllocator; +class MemoryAllocator { + friend class NearMemoryAllocator; + +private: + std::vector code_arenas; + std::vector data_arenas; + +private: + static MemoryAllocator *shared_allocator; + +public: + static MemoryAllocator *SharedAllocator(); + +public: + CodeMemoryArena *allocateCodeMemoryArena(uint32_t size); + CodeMemBlock *allocateExecBlock(uint32_t size); + uint8_t *allocateExecMemory(uint32_t size); + uint8_t *allocateExecMemory(uint8_t *buffer, uint32_t buffer_size); + + DataMemoryArena *allocateDataMemoryArena(uint32_t size); + DataMemBlock *allocateDataBlock(uint32_t size); + uint8_t *allocateDataMemory(uint32_t size); + uint8_t *allocateDataMemory(uint8_t *buffer, uint32_t buffer_size); +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h new file mode 100644 index 0000000..14db027 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h @@ -0,0 +1,39 @@ +#pragma once + +#include "dobby_internal.h" + +#ifdef ENABLE_CLOSURE_TRAMPOLINE_TEMPLATE +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus +void closure_trampoline_template(); +void closure_bridge_template(); +#ifdef __cplusplus +} +#endif //__cplusplus +#endif + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +typedef struct { + void *address; + int size; + void *carry_handler; + void *carry_data; +} ClosureTrampolineEntry; + +asm_func_t get_closure_bridge(); + +#ifdef __cplusplus +} +#endif //__cplusplus + +class ClosureTrampoline { +private: + static std::vector *trampolines_; + +public: + static ClosureTrampolineEntry *CreateClosureTrampoline(void *carry_data, void *carry_handler); +}; diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/ClosureTrampolineARM.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/ClosureTrampolineARM.cc new file mode 100644 index 0000000..25720ad --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/ClosureTrampolineARM.cc @@ -0,0 +1,49 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-arm.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +using namespace zz; +using namespace zz::arm; + +ClosureTrampolineEntry *ClosureTrampoline::CreateClosureTrampoline(void *carry_data, void *carry_handler) { + ClosureTrampolineEntry *tramp_entry = nullptr; + tramp_entry = new ClosureTrampolineEntry; + +#ifdef ENABLE_CLOSURE_TRAMPOLINE_TEMPLATE +#define CLOSURE_TRAMPOLINE_SIZE (7 * 4) + // use closure trampoline template code, find the executable memory and patch it. + auto code = AssemblyCodeBuilder::FinalizeCodeFromAddress(closure_trampoline_template, CLOSURE_TRAMPOLINE_SIZE); +#else +// use assembler and codegen modules instead of template_code +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" +#define _ turbo_assembler_. + TurboAssembler turbo_assembler_(0); + + AssemblerPseudoLabel entry_label; + AssemblerPseudoLabel forward_bridge_label; + + _ Ldr(r12, &entry_label); + _ Ldr(pc, &forward_bridge_label); + _ PseudoBind(&entry_label); + _ EmitAddress((uint32_t)(uintptr_t)tramp_entry); + _ PseudoBind(&forward_bridge_label); + _ EmitAddress((uint32_t)(uintptr_t)get_closure_bridge()); + + auto closure_tramp = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + tramp_entry->address = (void *)closure_tramp->addr; + tramp_entry->size = closure_tramp->size; + tramp_entry->carry_data = carry_data; + tramp_entry->carry_handler = carry_handler; + + delete closure_tramp; + + return tramp_entry; +#endif +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/closure_bridge_arm.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/closure_bridge_arm.cc new file mode 100644 index 0000000..1e0151e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/closure_bridge_arm.cc @@ -0,0 +1,90 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-arm.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h" + +using namespace zz; +using namespace zz::arm; + +static asm_func_t closure_bridge = nullptr; + +asm_func_t get_closure_bridge() { + + // if already initialized, just return. + if (closure_bridge) + return closure_bridge; + +// check if enable the inline-assembly closure_bridge_template +#if ENABLE_CLOSURE_BRIDGE_TEMPLATE + extern void closure_bridge_tempate(); + closure_bridge = closure_bridge_template; +// otherwise, use the Assembler build the closure_bridge +#else +#define _ turbo_assembler_. + TurboAssembler turbo_assembler_(0); + + _ sub(sp, sp, Operand(14 * 4)); + _ str(lr, MemOperand(sp, 13 * 4)); + _ str(r12, MemOperand(sp, 12 * 4)); + _ str(r11, MemOperand(sp, 11 * 4)); + _ str(r10, MemOperand(sp, 10 * 4)); + _ str(r9, MemOperand(sp, 9 * 4)); + _ str(r8, MemOperand(sp, 8 * 4)); + _ str(r7, MemOperand(sp, 7 * 4)); + _ str(r6, MemOperand(sp, 6 * 4)); + _ str(r5, MemOperand(sp, 5 * 4)); + _ str(r4, MemOperand(sp, 4 * 4)); + _ str(r3, MemOperand(sp, 3 * 4)); + _ str(r2, MemOperand(sp, 2 * 4)); + _ str(r1, MemOperand(sp, 1 * 4)); + _ str(r0, MemOperand(sp, 0 * 4)); + + // store sp + _ add(r0, sp, Operand(14 * 4)); + _ sub(sp, sp, Operand(8)); + _ str(r0, MemOperand(sp, 4)); + + // stack align + _ sub(sp, sp, Operand(8)); + + _ mov(r0, Operand(sp)); + _ mov(r1, Operand(r12)); + _ CallFunction(ExternalReference((void *)common_closure_bridge_handler)); + + // stack align + _ add(sp, sp, Operand(8)); + + // restore sp placeholder stack + _ add(sp, sp, Operand(8)); + + _ ldr(r0, MemOperand(sp, 4, PostIndex)); + _ ldr(r1, MemOperand(sp, 4, PostIndex)); + _ ldr(r2, MemOperand(sp, 4, PostIndex)); + _ ldr(r3, MemOperand(sp, 4, PostIndex)); + _ ldr(r4, MemOperand(sp, 4, PostIndex)); + _ ldr(r5, MemOperand(sp, 4, PostIndex)); + _ ldr(r6, MemOperand(sp, 4, PostIndex)); + _ ldr(r7, MemOperand(sp, 4, PostIndex)); + _ ldr(r8, MemOperand(sp, 4, PostIndex)); + _ ldr(r9, MemOperand(sp, 4, PostIndex)); + _ ldr(r10, MemOperand(sp, 4, PostIndex)); + _ ldr(r11, MemOperand(sp, 4, PostIndex)); + _ ldr(r12, MemOperand(sp, 4, PostIndex)); + _ ldr(lr, MemOperand(sp, 4, PostIndex)); + + // auto switch A32 & T32 with `least significant bit`, refer `docs/A32_T32_states_switch.md` + _ mov(pc, Operand(r12)); + + auto code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + closure_bridge = (asm_func_t)code->addr; + + DLOG(0, "[closure bridge] closure bridge at %p", closure_bridge); +#endif + return closure_bridge; +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/dummy/closure-bridge-template-arm.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/dummy/closure-bridge-template-arm.cc new file mode 100644 index 0000000..8e41525 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/dummy/closure-bridge-template-arm.cc @@ -0,0 +1,65 @@ +// .section __TEXT,__text,regular,pure_instructions +// .ios_version_min 11, 0 + +#if defined(ENABLE_CLOSURE_BRIDGE_TEMPLATE) + +#if defined(__WIN32__) || defined(__APPLE__) +#define cdecl(s) "_" s +#else +#define cdecl(s) s +#endif + +#define xASM(x) __asm(x) + +__attribute__((naked)) void closure_bridge_template() { + xASM(".arm"); + xASM("sub sp, sp, #(14*4)"); + xASM("str lr, [sp, #(13*4)]"); + xASM("str r12, [sp, #(12*4)]"); + xASM("str r11, [sp, #(11*4)]"); + xASM("str r10, [sp, #(10*4)]"); + xASM("str r9, [sp, #(9*4)]"); + xASM("str r8, [sp, #(8*4)]"); + xASM("str r7, [sp, #(7*4)]"); + xASM("str r6, [sp, #(6*4)]"); + xASM("str r5, [sp, #(5*4)]"); + xASM("str r4, [sp, #(4*4)]"); + xASM("str r3, [sp, #(3*4)]"); + xASM("str r2, [sp, #(2*4)]"); + xASM("str r1, [sp, #(1*4)]"); + xASM("str r0, [sp, #(0*4)]"); + + // dummy align + xASM("sub sp, sp, #8"); + + xASM("mov r0, sp"); + xASM("mov r1, r12"); + xASM("bl " cdecl("common_closure_bridge_handler")); + + // dummy align + xASM("add sp, sp, #8"); + + xASM("ldr r0, [sp], #4"); + xASM("ldr r1, [sp], #4"); + xASM("ldr r2, [sp], #4"); + xASM("ldr r3, [sp], #4"); + xASM("ldr r4, [sp], #4"); + xASM("ldr r5, [sp], #4"); + xASM("ldr r6, [sp], #4"); + xASM("ldr r7, [sp], #4"); + xASM("ldr r8, [sp], #4"); + xASM("ldr r9, [sp], #4"); + xASM("ldr r10, [sp], #4"); + xASM("ldr r11, [sp], #4"); + xASM("ldr r12, [sp], #4"); + xASM("ldr lr, [sp], #4"); + +#if 1 + xASM("str r12, [sp, #-4]"); + xASM("ldr pc, [sp, #-4]"); +#else + xASM("mov pc, r12"); +#endif +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/dummy/closure-trampoline-template-arm.S b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/dummy/closure-trampoline-template-arm.S new file mode 100644 index 0000000..2186324 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/dummy/closure-trampoline-template-arm.S @@ -0,0 +1,40 @@ +// .section __TEXT,__text,regular,pure_instructions + +#if defined(ENABLE_CLOSURE_BRIDGE_TEMPLATE) + +#if defined(__WIN32__) || defined(__APPLE__) +#define cdecl(s) _##s +#else +#define cdecl(s) s +#endif + +.align 4 + +#if !defined(ENABLE_CLOSURE_TRAMPOLINE_CARRY_OBJECT_PTR) + +// closure trampoline carray the object pointer, and fetch required members at the runtime assembly code. +// #include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" +// #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) +#define OFFSETOF_ClourseTrampolineEntry_carry_data 4 +#define OFFSETOF_ClourseTrampolineEntry_carry_handler 0 +.globl cdecl(closure_trampoline_template) +cdecl(closure_trampoline_template): + ldr r12, ClourseTrampolineEntryPtr + ldr pc, [r12, #0] +ClourseTrampolineEntryPtr: + .long 0 + +#else + +; closure trampoline just carray the required members from the object. +.globl cdecl(closure_trampoline_template) +cdecl(closure_trampoline_template): + ldr r12, =carry_data + ldr pc, =carry_handler +carry_data: + .long 0 +carry_handler: + .long 0 +#endif + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/helper_arm.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/helper_arm.cc new file mode 100644 index 0000000..cf93095 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm/helper_arm.cc @@ -0,0 +1,13 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM) + +#include "dobby_internal.h" + +void set_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address) { + *reinterpret_cast(&ctx->general.regs.r12) = address; +} + +void get_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address) { +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/ClosureTrampolineARM64.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/ClosureTrampolineARM64.cc new file mode 100644 index 0000000..6dcb702 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/ClosureTrampolineARM64.cc @@ -0,0 +1,63 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM64) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-arm64.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +using namespace zz; +using namespace zz::arm64; + +// // tips +// _ ldr(TMP_REG_1, OFFSETOF(ClosureTrampolineEntry, carry_data)); +// _ ldr(TMP_REG_0, OFFSETOF(ClosureTrampolineEntry, carry_handler)); + +// use assembler and codegen modules instead of template_code +ClosureTrampolineEntry *ClosureTrampoline::CreateClosureTrampoline(void *carry_data, void *carry_handler) { + ClosureTrampolineEntry *tramp_entry = nullptr; + tramp_entry = new ClosureTrampolineEntry; + +#define _ turbo_assembler_. + TurboAssembler turbo_assembler_(0); + + AssemblerPseudoLabel entry_label; + AssemblerPseudoLabel forward_bridge_label; + + // prologue: alloc stack, store lr + _ sub(SP, SP, 2 * 8); + _ str(x30, MemOperand(SP, 8)); + + // store data at stack + _ Ldr(TMP_REG_0, &entry_label); + _ str(TMP_REG_0, MemOperand(SP, 0)); + + _ Ldr(TMP_REG_0, &forward_bridge_label); + _ blr(TMP_REG_0); + + // epilogue: release stack(won't restore lr) + _ ldr(x30, MemOperand(SP, 8)); + _ add(SP, SP, 2 * 8); + + // branch to next hop + _ br(TMP_REG_0); + + _ PseudoBind(&entry_label); + _ EmitInt64((uint64_t)tramp_entry); + _ PseudoBind(&forward_bridge_label); + _ EmitInt64((uint64_t)get_closure_bridge()); + + auto closure_tramp = AssemblyCodeBuilder::FinalizeFromTurboAssembler(static_cast(&turbo_assembler_)); + + tramp_entry->address = (void *)closure_tramp->addr; + tramp_entry->size = closure_tramp->size; + tramp_entry->carry_data = carry_data; + tramp_entry->carry_handler = carry_handler; + + delete closure_tramp; + + return tramp_entry; +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/closure_bridge_arm64.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/closure_bridge_arm64.cc new file mode 100644 index 0000000..d9159af --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/closure_bridge_arm64.cc @@ -0,0 +1,159 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM64) + +#include "dobby_internal.h" + +#include "core/assembler/assembler.h" +#include "core/assembler/assembler-arm64.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h" + +using namespace zz; +using namespace zz::arm64; + +static asm_func_t closure_bridge = nullptr; + +asm_func_t get_closure_bridge() { + // if already initialized, just return. + if (closure_bridge) + return closure_bridge; + +// check if enable the inline-assembly closure_bridge_template +#if ENABLE_CLOSURE_BRIDGE_TEMPLATE + extern void closure_bridge_tempate(); + closure_bridge = closure_bridge_template; +// otherwise, use the Assembler build the closure_bridge +#else +#define _ turbo_assembler_. +#define MEM(reg, offset) MemOperand(reg, offset) + TurboAssembler turbo_assembler_(0); + +#if defined(FULL_FLOATING_POINT_REGISTER_PACK) + + _ sub(SP, SP, 24 * 16); + _ stp(Q(30), Q(31), MEM(SP, 22 * 16)); + _ stp(Q(28), Q(29), MEM(SP, 20 * 16)); + _ stp(Q(26), Q(27), MEM(SP, 18 * 16)); + _ stp(Q(24), Q(25), MEM(SP, 16 * 16)); + _ stp(Q(22), Q(23), MEM(SP, 14 * 16)); + _ stp(Q(20), Q(21), MEM(SP, 12 * 16)); + _ stp(Q(18), Q(19), MEM(SP, 10 * 16)); + _ stp(Q(16), Q(17), MEM(SP, 8 * 16)); + _ stp(Q(14), Q(15), MEM(SP, 6 * 16)); + _ stp(Q(12), Q(13), MEM(SP, 4 * 16)); + _ stp(Q(10), Q(11), MEM(SP, 2 * 16)); + _ stp(Q(8), Q(9), MEM(SP, 0 * 16)); + +#endif + + // save {q0-q7} + _ sub(SP, SP, 8 * 16); + _ stp(Q(6), Q(7), MEM(SP, 6 * 16)); + _ stp(Q(4), Q(5), MEM(SP, 4 * 16)); + _ stp(Q(2), Q(3), MEM(SP, 2 * 16)); + _ stp(Q(0), Q(1), MEM(SP, 0 * 16)); + + // save {x1-x30} + _ sub(SP, SP, 30 * 8); + _ stp(X(29), X(30), MEM(SP, 28 * 8)); + _ stp(X(27), X(28), MEM(SP, 26 * 8)); + _ stp(X(25), X(26), MEM(SP, 24 * 8)); + _ stp(X(23), X(24), MEM(SP, 22 * 8)); + _ stp(X(21), X(22), MEM(SP, 20 * 8)); + _ stp(X(19), X(20), MEM(SP, 18 * 8)); + _ stp(X(17), X(18), MEM(SP, 16 * 8)); + _ stp(X(15), X(16), MEM(SP, 14 * 8)); + _ stp(X(13), X(14), MEM(SP, 12 * 8)); + _ stp(X(11), X(12), MEM(SP, 10 * 8)); + _ stp(X(9), X(10), MEM(SP, 8 * 8)); + _ stp(X(7), X(8), MEM(SP, 6 * 8)); + _ stp(X(5), X(6), MEM(SP, 4 * 8)); + _ stp(X(3), X(4), MEM(SP, 2 * 8)); + _ stp(X(1), X(2), MEM(SP, 0 * 8)); + + // save {x0} + _ sub(SP, SP, 2 * 8); + _ str(x0, MEM(SP, 8)); + + // calculate original sp + _ add(TMP_REG_0, SP, 2 * 8); // closure trampoline reserved + _ add(TMP_REG_0, TMP_REG_0, 2 * 8 + 30 * 8 + 8 * 16); // x0, x1-x30, q0-q7 reserved +#if defined(FULL_FLOATING_POINT_REGISTER_PACK) + _ add(TMP_REG_0, TMP_REG_0, 24 * 16); // q8-q31 reserved +#endif + + // alloc stack, store original sp + _ sub(SP, SP, 2 * 8); + _ str(TMP_REG_0, MEM(SP, 8)); + +#if defined(FULL_FLOATING_POINT_REGISTER_PACK) +#define REGISTER_CONTEXT_SIZE (sizeof(DobbyRegisterContext)) +#else +#define REGISTER_CONTEXT_SIZE (sizeof(DobbyRegisterContext) - 24 * 16) +#endif + // create function arm64 call convention + _ mov(x0, SP); // arg1: register context + // load package(closure trampoline entry reserved) + _ ldr(x1, MEM(SP, REGISTER_CONTEXT_SIZE + 0)); // arg2: closure trampoline entry + _ CallFunction(ExternalReference((void *)common_closure_bridge_handler)); + + // restore sp placeholder stack + _ add(SP, SP, 2 * 8); + + // restore {x0} + _ ldr(X(0), MEM(SP, 8)); + _ add(SP, SP, 2 * 8); + +#define MEM_EXT(reg, offset, addrmode) MemOperand(reg, offset, addrmode) + // restore {x1-x30} + _ ldp(X(1), X(2), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(3), X(4), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(5), X(6), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(7), X(8), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(9), X(10), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(11), X(12), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(13), X(14), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(15), X(16), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(17), X(18), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(19), X(20), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(21), X(22), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(23), X(24), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(25), X(26), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(27), X(28), MEM_EXT(SP, 16, PostIndex)); + _ ldp(X(29), X(30), MEM_EXT(SP, 16, PostIndex)); + + // restore {q0-q7} + _ ldp(Q(0), Q(1), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(2), Q(3), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(4), Q(5), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(6), Q(7), MEM_EXT(SP, 32, PostIndex)); + +#if defined(FULL_FLOATING_POINT_REGISTER_PACK) + _ ldp(Q(8), Q(9), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(10), Q(11), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(12), Q(13), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(14), Q(15), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(16), Q(17), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(18), Q(19), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(20), Q(21), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(22), Q(23), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(24), Q(25), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(26), Q(27), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(28), Q(29), MEM_EXT(SP, 32, PostIndex)); + _ ldp(Q(30), Q(31), MEM_EXT(SP, 32, PostIndex)); +#endif + + // _ brk(0); // for debug + + // return to closure trampoline, but TMP_REG_0, had been modified with next hop address + _ ret(); // AKA br x30 + + auto code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + closure_bridge = (asm_func_t)code->addr; + + DLOG(0, "[closure bridge] closure bridge at %p", closure_bridge); +#endif + return closure_bridge; +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/closure-bridge-template-arm64.c b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/closure-bridge-template-arm64.c new file mode 100644 index 0000000..ee5323e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/closure-bridge-template-arm64.c @@ -0,0 +1,103 @@ +#if defined(ENABLE_CLOSURE_BRIDGE_TEMPLATE) + +#if defined(__WIN32__) || defined(__APPLE__) +#define xcdecl(s) "_" s +#else +#define xcdecl(s) s +#endif + +#define xASM(x) __asm(x) + +__attribute__((naked)) void closure_bridge_template() { + // DO NOT USE prologue + // x29 == fp, x30 == lr + // xASM("stp x29, x30, [sp, #-16]!"); + // xASM("mov x29, sp"); + + // save {q0-q7} + xASM("sub sp, sp, #(8*16)"); + xASM("stp q6, q7, [sp, #(6*16)]"); + xASM("stp q4, q5, [sp, #(4*16)]"); + xASM("stp q2, q3, [sp, #(2*16)]"); + xASM("stp q0, q1, [sp, #(0*16)]"); + + // save {x1-x30} + xASM("sub sp, sp, #(30*8)"); + // stp fp, lr, [sp, #(28*8)]"); + xASM("stp x29, x30, [sp, #(28*8)]"); + xASM("stp x27, x28, [sp, #(26*8)]"); + xASM("stp x25, x26, [sp, #(24*8)]"); + xASM("stp x23, x24, [sp, #(22*8)]"); + xASM("stp x21, x22, [sp, #(20*8)]"); + xASM("stp x19, x20, [sp, #(18*8)]"); + xASM("stp x17, x18, [sp, #(16*8)]"); + xASM("stp x15, x16, [sp, #(14*8)]"); + xASM("stp x13, x14, [sp, #(12*8)]"); + xASM("stp x11, x12, [sp, #(10*8)]"); + xASM("stp x9, x10, [sp, #(8*8)]"); + xASM("stp x7, x8, [sp, #(6*8)]"); + xASM("stp x5, x6, [sp, #(4*8)]"); + xASM("stp x3, x4, [sp, #(2*8)]"); + xASM("stp x1, x2, [sp, #(0*8)]"); + +#if 1 + // save {x0} + xASM("sub sp, sp, #(2*8)"); + xASM("str x0, [sp, #8]"); +#else + // save {x0, sp} + // save x0 and reserve sp, but this is trick + xASM("sub sp, sp, #(2*8)"); + xASM("str x0, [sp, #8]"); + // save origin sp + xASM("add x1, sp, #0x190"); + xASM("str x1, [sp, #0]"); +#endif + + // ======= Jump to UnifiedInterface Bridge Handle ======= + + // prepare args + // @x0: data_address + // @x1: DobbyRegisterContext stack address + xASM("mov x0, sp"); + xASM("mov x1, x14"); + xASM("bl " xcdecl("common_closure_bridge_handler")); + + // ======= DobbyRegisterContext Restore ======= + // restore x0 + xASM("ldr x0, [sp, #8]"); + xASM("add sp, sp, #(2*8)"); + + // restore {x1-x30} + xASM("ldp x1, x2, [sp], #16"); + xASM("ldp x3, x4, [sp], #16"); + xASM("ldp x5, x6, [sp], #16"); + xASM("ldp x7, x8, [sp], #16"); + xASM("ldp x9, x10, [sp], #16"); + xASM("ldp x11, x12, [sp], #16"); + xASM("ldp x13, x14, [sp], #16"); + xASM("ldp x15, x16, [sp], #16"); + xASM("ldp x17, x18, [sp], #16"); + xASM("ldp x19, x20, [sp], #16"); + xASM("ldp x21, x22, [sp], #16"); + xASM("ldp x23, x24, [sp], #16"); + xASM("ldp x25, x26, [sp], #16"); + xASM("ldp x27, x28, [sp], #16"); + // ldp fp, lr, [sp], #16"); + xASM("ldp x29, x30, [sp], #16"); + + // restore {q0-q7} + xASM("ldp q0, q1, [sp], #32"); + xASM("ldp q2, q3, [sp], #32"); + xASM("ldp q4, q5, [sp], #32"); + xASM("ldp q6, q7, [sp], #32"); + + // DO NOT USE epilog + // x29 == fp, x30 == lr + // xASM("mov sp, x29"); + // xASM("ldp x29, x30, [sp], #16"); + + xASM("br x15"); +}; + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/closure-trampoline-template-arm64.S b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/closure-trampoline-template-arm64.S new file mode 100644 index 0000000..16116cf --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/closure-trampoline-template-arm64.S @@ -0,0 +1,47 @@ +// .section __TEXT,__text,regular,pure_instructions + +#if defined(ENABLE_CLOSURE_BRIDGE_TEMPLATE) + +#if defined(__WIN32__) || defined(__APPLE__) +#define cdecl(s) _##s +#else +#define cdecl(s) s +#endif + +.align 4 + +#if !defined(ENABLE_CLOSURE_TRAMPOLINE_CARRY_OBJECT_PTR) + +// closure trampoline carray the object pointer, and fetch required members at the runtime assembly code. +// #include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" +// #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) +#define OFFSETOF_ClourseTrampolineEntry_carry_data 8 +#define OFFSETOF_ClourseTrampolineEntry_carry_handler 0 +.globl cdecl(closure_trampoline_template) +cdecl(closure_trampoline_template): + ldr x17, ClourseTrampolineEntryPtr + ldr x16, OFFSETOF_ClourseTrampolineEntry_carry_data + ldr x17, OFFSETOF_ClourseTrampolineEntry_carry_handler + br x17 +ClourseTrampolineEntryPtr: + .long 0 + .long 0 + +#else + +; closure trampoline just carray the required members from the object. +.globl cdecl(closure_trampoline_template) +cdecl(closure_trampoline_template): + ldr x16, =carry_data + ldr x17, =carry_handler + br x17 +carry_data: + .long 0 + .long 0 +carry_handler: + .long 0 + .long 0 + +#endif + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/dynamic-closure-trampoline-template-arm64.S b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/dynamic-closure-trampoline-template-arm64.S new file mode 100644 index 0000000..593b57b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/dummy/dynamic-closure-trampoline-template-arm64.S @@ -0,0 +1,31 @@ +// .section __TEXT,__text,regular,pure_instructions + +// For iOS, we can't allocate executable memory, but we can use `remap` doing some trick. +// For details, please refer `libffi` + +#if defined(ENABLE_CLOSURE_BRIDGE_TEMPLATE) + +#if defined(__WIN32__) || defined(__APPLE__) + #define cdecl(s) _##s +#else + #define cdecl(s) s +#endif + +#define PAGE_MAX_SIZE 4096 +#define PAGE_MAX_SHIFT 14 + +.align PAGE_MAX_SHIFT +.globl cdecl(dynamic_closure_trampoline_table_page) +cdecl(dynamic_closure_trampoline_table_page): +.rept (PAGE_MAX_SIZE - 4 * 4) / 8 // sub dynamic_closure_trampoline_forward size +adr x16, #0 +b cdecl(dynamic_closure_trampoline_forward) +.endr + +cdecl(dynamic_closure_trampoline_forward): +sub x16, x16, #0x4000 // [DynamicClosureTrampoline **] +ldr x16, [x16, #0] // [DynamicClosureTrampoline *] +ldr x17, [x16, #0] // trampolineTo +br x17 + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/helper_arm64.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/helper_arm64.cc new file mode 100644 index 0000000..8a9fabb --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/arm64/helper_arm64.cc @@ -0,0 +1,17 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM64) + +#include "core/assembler/assembler-arm64.h" + +#include "dobby_internal.h" + +using namespace zz::arm64; + +void set_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address) { + *reinterpret_cast(&ctx->general.x[TMP_REG_0.code()]) = address; +} + +void get_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address) { +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.cc new file mode 100644 index 0000000..5fdf917 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.cc @@ -0,0 +1,22 @@ +#include "logging/logging.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h" + +PUBLIC void common_closure_bridge_handler(DobbyRegisterContext *ctx, ClosureTrampolineEntry *entry) { + DLOG(0, "common bridge handler: carry data: %p, carry handler: %p", (InterceptEntry *)entry->carry_data, + entry->carry_handler); + + typedef void (*routing_handler_t)(InterceptEntry *, DobbyRegisterContext *); + auto routing_handler = (routing_handler_t)entry->carry_handler; + +#if defined(__APPLE__) && __arm64e__ +#if __has_feature(ptrauth_calls) + uint64_t discriminator = 0; + // discriminator = __builtin_ptrauth_type_discriminator(__typeof(routing_handler)); + routing_handler = (__typeof(routing_handler))__builtin_ptrauth_sign_unauthenticated((void *)routing_handler, + ptrauth_key_asia, discriminator); +#endif +#endif + + routing_handler((InterceptEntry *)entry->carry_data, ctx); +} diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h new file mode 100644 index 0000000..52d8567 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h @@ -0,0 +1,17 @@ +#ifndef CLOSURE_TRAMPOLINE_COMMON_HANDLER_H +#define CLOSURE_TRAMPOLINE_COMMON_HANDLER_H + +#include "dobby_internal.h" + +#include "Interceptor.h" +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +extern "C" { +void common_closure_bridge_handler(DobbyRegisterContext *ctx, ClosureTrampolineEntry *entry); +} + +void get_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address); + +void set_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address); + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/ClosureTrampolineX64.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/ClosureTrampolineX64.cc new file mode 100644 index 0000000..2b8cc8c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/ClosureTrampolineX64.cc @@ -0,0 +1,45 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_X64) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-x64.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +using namespace zz; +using namespace zz::x64; + +ClosureTrampolineEntry *ClosureTrampoline::CreateClosureTrampoline(void *carry_data, void *carry_handler) { + ClosureTrampolineEntry *tramp_entry = nullptr; + tramp_entry = new ClosureTrampolineEntry; + + auto tramp_size = 32; + auto tramp_mem = MemoryAllocator::SharedAllocator()->allocateExecMemory(tramp_size); + if (tramp_mem == nullptr) { + return nullptr; + } +#define _ turbo_assembler_. +#define __ turbo_assembler_.GetCodeBuffer()-> + TurboAssembler turbo_assembler_(0); + + uint8_t *push_rip_6 = (uint8_t *)"\xff\x35\x06\x00\x00\x00"; + uint8_t *jmp_rip_8 = (uint8_t *)"\xff\x25\x08\x00\x00\x00"; + + __ EmitBuffer(push_rip_6, 6); + __ EmitBuffer(jmp_rip_8, 6); + __ Emit64((uint64_t)tramp_entry); + __ Emit64((uint64_t)get_closure_bridge()); + + tramp_entry->address = tramp_mem; + tramp_entry->size = tramp_size; + tramp_entry->carry_data = carry_data; + tramp_entry->carry_handler = carry_handler; + + auto closure_tramp_buffer = static_cast(turbo_assembler_.GetCodeBuffer()); + DobbyCodePatch(tramp_mem, (uint8_t *)closure_tramp_buffer->GetBuffer(), closure_tramp_buffer->GetBufferSize()); + + return tramp_entry; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/closure_bridge_x64.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/closure_bridge_x64.cc new file mode 100644 index 0000000..dc82f99 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/closure_bridge_x64.cc @@ -0,0 +1,141 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_X64) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-x64.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h" + +using namespace zz; +using namespace zz::x64; + +static asm_func_t closure_bridge = nullptr; + +asm_func_t get_closure_bridge() { + // if already initialized, just return. + if (closure_bridge) + return closure_bridge; + +// Check if enable the inline-assembly closure_bridge_template +#if ENABLE_CLOSURE_BRIDGE_TEMPLATE + + extern void closure_bridge_tempate(); + closure_bridge = closure_bridge_template; + +#else + +// otherwise, use the Assembler build the closure_bridge +#define _ turbo_assembler_. +#define __ turbo_assembler_.GetCodeBuffer()-> + + uint8_t *pushfq = (uint8_t *)"\x9c"; + uint8_t *popfq = (uint8_t *)"\x9d"; + + TurboAssembler turbo_assembler_(0); + + // save flags register + __ EmitBuffer(pushfq, 1); + // align rsp 16-byte + _ sub(rsp, Immediate(8, 32)); + + // general register + _ sub(rsp, Immediate(16 * 8, 32)); + _ mov(Address(rsp, 8 * 0), rax); + _ mov(Address(rsp, 8 * 1), rbx); + _ mov(Address(rsp, 8 * 2), rcx); + _ mov(Address(rsp, 8 * 3), rdx); + _ mov(Address(rsp, 8 * 4), rbp); + _ mov(Address(rsp, 8 * 5), rsp); + _ mov(Address(rsp, 8 * 6), rdi); + _ mov(Address(rsp, 8 * 7), rsi); + _ mov(Address(rsp, 8 * 8), r8); + _ mov(Address(rsp, 8 * 9), r9); + _ mov(Address(rsp, 8 * 10), r10); + _ mov(Address(rsp, 8 * 11), r11); + _ mov(Address(rsp, 8 * 12), r12); + _ mov(Address(rsp, 8 * 13), r13); + _ mov(Address(rsp, 8 * 14), r14); + _ mov(Address(rsp, 8 * 15), r15); + + // save origin sp + _ mov(rax, rsp); + _ add(rax, Immediate(8 + 8 + 8 + 16 * 8, 32)); + _ sub(rsp, Immediate(2 * 8, 32)); + _ mov(Address(rsp, 8), rax); + + // ======= Jump to UnifiedInterface Bridge Handle ======= + + // prepare args + // @rdi: data_address + // @rsi: DobbyRegisterContext stack address + _ mov(rdi, rsp); + _ mov(rsi, Address(rsp, 8 + 8 + 16 * 8 + 2 * 8)); + + // [!!!] As we can't detect the sp is aligned or not, check if need stack align + { + // mov rax, rsp + __ EmitBuffer((uint8_t *)"\x48\x89\xE0", 3); + // and rax, 0xF + __ EmitBuffer((uint8_t *)"\x48\x83\xE0\x0F", 4); + // cmp rax, 0x0 + __ EmitBuffer((uint8_t *)"\x48\x83\xF8\x00", 4); + // jnz [stack_align_call_bridge] + __ EmitBuffer((uint8_t *)"\x75\x15", 2); + } + + // LABEL: call_bridge + _ CallFunction(ExternalReference((void *)common_closure_bridge_handler)); + + // jmp [restore_stack_register] + __ EmitBuffer((uint8_t *)"\xE9\x12\x00\x00\x00", 5); + + // LABEL: stack_align_call_bridge + // push rax + __ EmitBuffer((uint8_t *)"\x50", 1); + _ CallFunction(ExternalReference((void *)common_closure_bridge_handler)); + // pop rax + __ EmitBuffer((uint8_t *)"\x58", 1); + + // ======= DobbyRegisterContext Restore ======= + + // restore sp placeholder stack + _ add(rsp, Immediate(2 * 8, 32)); + + // general register + _ pop(rax); + _ pop(rbx); + _ pop(rcx); + _ pop(rdx); + _ pop(rbp); + _ add(rsp, Immediate(8, 32)); // => pop rsp + _ pop(rdi); + _ pop(rsi); + _ pop(r8); + _ pop(r9); + _ pop(r10); + _ pop(r11); + _ pop(r12); + _ pop(r13); + _ pop(r14); + _ pop(r15); + + // align rsp 16-byte + _ add(rsp, Immediate(8, 32)); + // restore flags register + __ EmitBuffer(popfq, 1); + + // trick: use the 'carry_data' stack(remain at closure trampoline) placeholder, as the return address + _ ret(); + + _ RelocBind(); + + auto code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + closure_bridge = (asm_func_t)code->addr; + + DLOG(0, "[closure bridge] closure bridge at %p", closure_bridge); +#endif + return closure_bridge; +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/dummy/closure-bridge-template-x64.c b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/dummy/closure-bridge-template-x64.c new file mode 100644 index 0000000..d59dcdc --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/dummy/closure-bridge-template-x64.c @@ -0,0 +1,70 @@ +#if defined(ENABLE_CLOSURE_BRIDGE_TEMPLATE) + +#if defined(__WIN32__) || defined(__APPLE__) +#define xcdecl(s) "_" s +#else +#define xcdecl(s) s +#endif + +#define xASM(x) __asm(x) + +__attribute__((naked)) void closure_bridge_template() { + // flags register + xASM("pushfq"); + + // general register + xASM("sub rsp, #(16*8)"); + xASM("mov [rsp+16*0], rax"); + xASM("mov [rsp+16*1], rbx"); + xASM("mov [rsp+16*2], rcx"); + xASM("mov [rsp+16*3], rdx"); + xASM("mov [rsp+16*4], rbp"); + xASM("mov [rsp+16*5], rsp"); + xASM("mov [rsp+16*6], rdi"); + xASM("mov [rsp+16*7], rsi"); + xASM("mov [rsp+16*8], r8"); + xASM("mov [rsp+16*9], r9"); + xASM("mov [rsp+16*10], r10"); + xASM("mov [rsp+16*11], r11"); + xASM("mov [rsp+16*12], r12"); + xASM("mov [rsp+16*13], r13"); + xASM("mov [rsp+16*14], r14"); + xASM("mov [rsp+16*15], r15"); + + // ======= Jump to UnifiedInterface Bridge Handle ======= + + // prepare args + // @rdi: data_address + // @rsi: DobbyRegisterContext stack address + xASM("mov rdi, rsp"); + xASM("mov rsi, [rsp-16*8]"); + xASM("call " xcdecl("common_closure_bridge_handler")); + + // ======= DobbyRegisterContext Restore ======= + + // general register + xASM("pop r15"); + xASM("pop r14"); + xASM("pop r13"); + xASM("pop r12"); + xASM("pop r11"); + xASM("pop r10"); + xASM("pop r9"); + xASM("pop r8"); + xASM("pop rsi"); + xASM("pop rdi"); + xASM("pop rsp"); + xASM("pop rbp"); + xASM("pop rdx"); + xASM("pop rcx"); + xASM("pop rbx"); + xASM("pop rax"); + + // flags register + xASM("popfq"); + + // trick: use the 'carry_data' placeholder, as the return address + xASM("ret"); +}; + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/dummy/closure-trampoline-template-x64.S b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/dummy/closure-trampoline-template-x64.S new file mode 100644 index 0000000..b24b602 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/dummy/closure-trampoline-template-x64.S @@ -0,0 +1,23 @@ +#if defined(ENABLE_CLOSURE_BRIDGE_TEMPLATE) + +#if defined(__WIN32__) || defined(__APPLE__) +#define cdecl(s) _##s +#else +#define cdecl(s) s +#endif + +.align 4 + +; closure trampoline just carray the required members from the object. +.globl cdecl(closure_trampoline_template) +cdecl(closure_trampoline_template): + push [rip+6+6] + jmp [rip+6+8] +carry_data: + .long 0 + .long 0 +carry_handler: + .long 0 + .long 0 + +#endif diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/helper_x64.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/helper_x64.cc new file mode 100644 index 0000000..383651f --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x64/helper_x64.cc @@ -0,0 +1,17 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_X64) + +#include "dobby_internal.h" + +void set_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address) { + addr_t rsp = ctx->rsp; + + // ClosureTrampolineEntry reserved stack + addr_t entry_placeholder_stack_addr = rsp - 8; + *(addr_t *)entry_placeholder_stack_addr = (addr_t)address; +} + +void get_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address) { +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/ClosureTrampolineX86.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/ClosureTrampolineX86.cc new file mode 100644 index 0000000..be86bbe --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/ClosureTrampolineX86.cc @@ -0,0 +1,44 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-ia32.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/ClosureTrampoline.h" + +using namespace zz; +using namespace zz::x86; + +ClosureTrampolineEntry *ClosureTrampoline::CreateClosureTrampoline(void *carry_data, void *carry_handler) { + ClosureTrampolineEntry *tramp_entry = nullptr; + tramp_entry = new ClosureTrampolineEntry; + + auto tramp_size = 32; + auto tramp_mem = MemoryAllocator::SharedAllocator()->allocateExecMemory(tramp_size); + if (tramp_mem == nullptr) { + return nullptr; + } + +#define _ turbo_assembler_. +#define __ turbo_assembler_.GetCodeBuffer()-> + TurboAssembler turbo_assembler_(tramp_mem); + + int32_t offset = (int32_t)((uintptr_t)get_closure_bridge() - ((uintptr_t)tramp_mem + 18)); + + _ sub(esp, Immediate(4, 32)); + _ mov(Address(esp, 4 * 0), Immediate((int32_t)(uintptr_t)tramp_entry, 32)); + _ jmp(Immediate(offset, 32)); + + tramp_entry->address = tramp_mem; + tramp_entry->size = tramp_size; + tramp_entry->carry_data = carry_data; + tramp_entry->carry_handler = carry_handler; + + auto closure_tramp_buffer = static_cast(turbo_assembler_.GetCodeBuffer()); + DobbyCodePatch(tramp_mem, (uint8_t *)closure_tramp_buffer->GetBuffer(), closure_tramp_buffer->GetBufferSize()); + + return tramp_entry; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/closure_bridge_x86.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/closure_bridge_x86.cc new file mode 100644 index 0000000..3e03b57 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/closure_bridge_x86.cc @@ -0,0 +1,112 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-ia32.h" + +#include "TrampolineBridge/ClosureTrampolineBridge/common_bridge_handler.h" + +using namespace zz; +using namespace zz::x86; + +static asm_func_t closure_bridge = NULL; + +asm_func_t get_closure_bridge() { + // if already initialized, just return. + if (closure_bridge) + return closure_bridge; + +// Check if enable the inline-assembly closure_bridge_template +#if ENABLE_CLOSURE_BRIDGE_TEMPLATE + + extern void closure_bridge_tempate(); + closure_bridge = closure_bridge_template; + +#else + +// otherwise, use the Assembler build the closure_bridge +#define _ turbo_assembler_. +#define __ turbo_assembler_.GetCodeBuffer()-> + + auto pushfd = (uint8_t *)"\x9c"; + auto popfd = (uint8_t *)"\x9d"; + + TurboAssembler turbo_assembler_(0); + + // general register + _ sub(esp, Immediate(8 * 4, 32)); + _ mov(Address(esp, 4 * 0), eax); + _ mov(Address(esp, 4 * 1), ebx); + _ mov(Address(esp, 4 * 2), ecx); + _ mov(Address(esp, 4 * 3), edx); + _ mov(Address(esp, 4 * 4), ebp); + _ mov(Address(esp, 4 * 5), esp); + _ mov(Address(esp, 4 * 6), edi); + _ mov(Address(esp, 4 * 7), esi); + + // save flags register + __ EmitBuffer(pushfd, 1); + _ pop(eax); + { // save to stack + _ sub(esp, Immediate(2 * 4, 32)); + _ mov(Address(esp, 4), eax); + } + + // save origin sp + _ mov(eax, esp); + _ add(eax, Immediate(8 * 4 + 2 * 4 + 4, 32)); + { // save to stack + _ sub(esp, Immediate(2 * 4, 32)); + _ mov(Address(esp, 4), eax); + } + + // ======= Jump to UnifiedInterface Bridge Handle ======= + + // prepare args + _ sub(esp, Immediate(2 * 4, 32)); + _ mov(eax, Address(esp, 8 * 4 + 2 * 4 + 2 * 4 + 2 * 4)); + _ mov(Address(esp, 4), eax); + _ mov(eax, esp); + _ add(eax, Immediate(2 * 4, 32)); + _ mov(Address(esp, 0), eax); + + // LABEL: call_bridge + _ CallFunction(ExternalReference((void *)common_closure_bridge_handler)); + + // ======= DobbyRegisterContext Restore ======= + + // restore argument reserved stack + _ add(esp, Immediate(2 * 4, 32)); + + // restore sp placeholder stack + _ add(esp, Immediate(2 * 4, 32)); + + _ add(esp, Immediate(4, 32)); + // restore flags register + __ EmitBuffer(popfd, 1); + + // general register + _ pop(eax); + _ pop(ebx); + _ pop(ecx); + _ pop(edx); + _ pop(ebp); + _ add(esp, Immediate(4, 32)); // => pop rsp + _ pop(edi); + _ pop(esi); + + // trick: use the 'carry_data' stack(remain at closure trampoline) placeholder, as the return address + _ ret(); + + _ RelocBind(); + + auto code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_); + closure_bridge = (asm_func_t)code->addr; + + DLOG(0, "[closure bridge] closure bridge at %p", closure_bridge); +#endif + return closure_bridge; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/helper_x86.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/helper_x86.cc new file mode 100644 index 0000000..5bf2529 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/ClosureTrampolineBridge/x86/helper_x86.cc @@ -0,0 +1,16 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) + +#include "dobby_internal.h" + +void set_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address) { + addr_t esp = ctx->esp; + + addr_t entry_placeholder_stack_addr = esp - 4; + *(addr_t *)entry_placeholder_stack_addr = (addr_t)address; +} + +void get_routing_bridge_next_hop(DobbyRegisterContext *ctx, void *address) { +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/Trampoline.h b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/Trampoline.h new file mode 100644 index 0000000..53f3779 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/Trampoline.h @@ -0,0 +1,5 @@ +#pragma once + +#include "MemoryAllocator/AssemblyCodeBuilder.h" + +CodeBufferBase *GenerateNormalTrampolineBuffer(addr_t from, addr_t to); \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/arm/trampoline_arm.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/arm/trampoline_arm.cc new file mode 100644 index 0000000..f291302 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/arm/trampoline_arm.cc @@ -0,0 +1,61 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-arm.h" +#include "core/codegen/codegen-arm.h" + +#include "InstructionRelocation/arm/InstructionRelocationARM.h" +#include "MemoryAllocator/NearMemoryAllocator.h" +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +using namespace zz::arm; + +static CodeBufferBase *generate_arm_trampoline(addr32_t from, addr32_t to) { + TurboAssembler turbo_assembler_((void *)from); +#define _ turbo_assembler_. + + CodeGen codegen(&turbo_assembler_); + codegen.LiteralLdrBranch(to); + + return turbo_assembler_.GetCodeBuffer()->Copy(); +} + +CodeBufferBase *generate_thumb_trampoline(addr32_t from, addr32_t to) { + ThumbTurboAssembler thumb_turbo_assembler_((void *)from); +#undef _ +#define _ thumb_turbo_assembler_. + + _ AlignThumbNop(); + _ t2_ldr(pc, MemOperand(pc, 0)); + _ EmitAddress(to); + + return thumb_turbo_assembler_.GetCodeBuffer()->Copy(); +} + +CodeBufferBase *GenerateNormalTrampolineBuffer(addr_t from, addr_t to) { + enum ExecuteState { ARMExecuteState, ThumbExecuteState }; + + // set instruction running state + ExecuteState execute_state_; + execute_state_ = ARMExecuteState; + if ((addr_t)from % 2) { + execute_state_ = ThumbExecuteState; + } + + if (execute_state_ == ARMExecuteState) { + return generate_arm_trampoline(from, to); + } else { + // Check if needed pc align, (relative pc instructions needed 4 align) + from = from - THUMB_ADDRESS_FLAG; + return generate_thumb_trampoline(from, to); + } + return NULL; +} + +CodeBufferBase *GenerateNearTrampolineBuffer(InterceptRouting *routing, addr_t src, addr_t dst) { + return NULL; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/arm64/trampoline_arm64.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/arm64/trampoline_arm64.cc new file mode 100644 index 0000000..c921683 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/arm64/trampoline_arm64.cc @@ -0,0 +1,41 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM64) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-arm64.h" +#include "core/codegen/codegen-arm64.h" + +#include "MemoryAllocator/NearMemoryAllocator.h" +#include "InstructionRelocation/arm64/InstructionRelocationARM64.h" +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +using namespace zz::arm64; + +CodeBufferBase *GenerateNormalTrampolineBuffer(addr_t from, addr_t to) { + TurboAssembler turbo_assembler_((void *)from); +#define _ turbo_assembler_. + + uint64_t distance = llabs((int64_t)(from - to)); + uint64_t adrp_range = ((uint64_t)1 << (2 + 19 + 12 - 1)); + if (distance < adrp_range) { + // adrp, add, br + _ AdrpAdd(TMP_REG_0, from, to); + _ br(TMP_REG_0); + DLOG(0, "[trampoline] use [adrp, add, br]"); + } else { + // ldr, br, branch-address + CodeGen codegen(&turbo_assembler_); + codegen.LiteralLdrBranch((uint64_t)to); + DLOG(0, "[trampoline] use [ldr, br, #label]"); + } +#undef _ + + // Bind all labels + turbo_assembler_.RelocBind(); + + auto result = turbo_assembler_.GetCodeBuffer()->Copy(); + return result; +} + +#endif diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/x64/trampoline_x64.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/x64/trampoline_x64.cc new file mode 100644 index 0000000..92c7009 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/x64/trampoline_x64.cc @@ -0,0 +1,54 @@ +#include "platform_macro.h" + +#if defined(TARGET_ARCH_X64) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-x64.h" +#include "core/codegen/codegen-x64.h" + +#include "InstructionRelocation/x64/InstructionRelocationX64.h" + +#include "MemoryAllocator/NearMemoryAllocator.h" +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +using namespace zz::x64; + +static addr_t allocate_indirect_stub(addr_t jmp_insn_addr) { + uint32_t jmp_near_range = (uint32_t)2 * 1024 * 1024 * 1024; + auto stub_addr = (addr_t)NearMemoryAllocator::SharedAllocator()->allocateNearDataMemory(sizeof(void *), jmp_insn_addr, + jmp_near_range); + if (stub_addr == 0) { + ERROR_LOG("Not found near forward stub"); + return 0; + } + + DLOG(0, "forward stub: %p", stub_addr); + return stub_addr; +} + +CodeBufferBase *GenerateNormalTrampolineBuffer(addr_t from, addr_t to) { + TurboAssembler turbo_assembler_((void *)from); +#define _ turbo_assembler_. + + // allocate forward stub + auto jump_near_next_insn_addr = from + 6; + addr_t forward_stub = allocate_indirect_stub(jump_near_next_insn_addr); + if (forward_stub == 0) + return nullptr; + + *(addr_t *)forward_stub = to; + + CodeGen codegen(&turbo_assembler_); + codegen.JmpNearIndirect((addr_t)forward_stub); + + auto buffer = turbo_assembler_.GetCodeBuffer()->Copy(); + return buffer; +} + +CodeBufferBase *GenerateNearTrampolineBuffer(InterceptRouting *routing, addr_t src, addr_t dst) { + DLOG(0, "x64 near branch trampoline enable default"); + return nullptr; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/x86/trampoline_x86.cc b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/x86/trampoline_x86.cc new file mode 100644 index 0000000..289b013 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/TrampolineBridge/Trampoline/x86/trampoline_x86.cc @@ -0,0 +1,33 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) + +#include "dobby_internal.h" + +#include "core/assembler/assembler-ia32.h" +#include "core/codegen/codegen-ia32.h" + +#include "InstructionRelocation/x86/InstructionRelocationX86.h" + +#include "MemoryAllocator/NearMemoryAllocator.h" +#include "InterceptRouting/RoutingPlugin/RoutingPlugin.h" + +using namespace zz::x86; + +CodeBufferBase *GenerateNormalTrampolineBuffer(addr_t from, addr_t to) { + TurboAssembler turbo_assembler_((void *)from); +#define _ turbo_assembler_. + + CodeGen codegen(&turbo_assembler_); + codegen.JmpNear((uint32_t)to); + + CodeBufferBase *result = NULL; + result = turbo_assembler_.GetCodeBuffer()->Copy(); + return result; +} + +CodeBufferBase *GenerateNearTrampolineBuffer(InterceptRouting *routing, addr_t src, addr_t dst) { + DLOG(0, "x86 near branch trampoline enable default"); + return NULL; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/Cpu.cc b/app/src/main/cpp/Dobby/source/core/arch/Cpu.cc new file mode 100644 index 0000000..0716361 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/Cpu.cc @@ -0,0 +1,5 @@ + +#include "core/arch/Cpu.h" +#include "core/arch/CpuUtils.h" + +#include "xnucxx/LiteMemOpt.h" diff --git a/app/src/main/cpp/Dobby/source/core/arch/Cpu.h b/app/src/main/cpp/Dobby/source/core/arch/Cpu.h new file mode 100644 index 0000000..e0361a7 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/Cpu.h @@ -0,0 +1,7 @@ +#ifndef CORE_ARCH_CPU_H +#define CORE_ARCH_CPU_H + +#include "CpuRegister.h" +#include "CpuFeature.h" + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/arch/CpuFeature.cc b/app/src/main/cpp/Dobby/source/core/arch/CpuFeature.cc new file mode 100644 index 0000000..d29f176 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/CpuFeature.cc @@ -0,0 +1,7 @@ + +#include "core/arch/CpuFeature.h" +#include "logging/logging.h" + +void CpuFeatures::ClearCache(void *start, void *end) { + UNIMPLEMENTED(); +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/CpuFeature.h b/app/src/main/cpp/Dobby/source/core/arch/CpuFeature.h new file mode 100644 index 0000000..b9a0736 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/CpuFeature.h @@ -0,0 +1,19 @@ +#ifndef CORE_ARCH_CPU_FEATURE_H +#define CORE_ARCH_CPU_FEATURE_H + +#include "common_header.h" + +class CpuFeatures { +private: + static void FlushICache(void *start, size_t size) { + ClearCache(start, (void *)((addr_t)start + size)); + } + + static void FlushICache(void *start, void *end) { + ClearCache(start, end); + } + + static void ClearCache(void *start, void *end); +}; + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/arch/CpuRegister.cc b/app/src/main/cpp/Dobby/source/core/arch/CpuRegister.cc new file mode 100644 index 0000000..3617e4e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/CpuRegister.cc @@ -0,0 +1,10 @@ + +#include "CpuRegister.h" + +constexpr RegisterBase RegisterBase::from_code(int code) { + return RegisterBase{code}; +} + +constexpr RegisterBase RegisterBase::no_reg() { + return RegisterBase{0}; +} \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/CpuRegister.h b/app/src/main/cpp/Dobby/source/core/arch/CpuRegister.h new file mode 100644 index 0000000..e12aff4 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/CpuRegister.h @@ -0,0 +1,25 @@ +#ifndef CORE_ARCH_CPU_REGISTER_H +#define CORE_ARCH_CPU_REGISTER_H + +class RegisterBase { +public: + static constexpr RegisterBase from_code(int code); + + static constexpr RegisterBase no_reg(); + + virtual bool Is(const RegisterBase ®) const { + return (reg.reg_code_ == this->reg_code_); + } + + int code() const { + return reg_code_; + }; + +protected: + explicit constexpr RegisterBase(int code) : reg_code_(code) { + } + + int reg_code_; +}; + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/arch/CpuUtils.h b/app/src/main/cpp/Dobby/source/core/arch/CpuUtils.h new file mode 100644 index 0000000..3942363 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/CpuUtils.h @@ -0,0 +1,17 @@ +#ifndef CPU_UTILITY_H +#define CPU_UTILITY_H + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__)) + +#if defined(__i386__) || defined(__x86_64__) +static __inline__ void __DEFAULT_FN_ATTRS __cpuid(int __info[4], int __level) { + __asm__("cpuid" : "=a"(__info[0]), "=b"(__info[1]), "=c"(__info[2]), "=d"(__info[3]) : "a"(__level)); +} + +static __inline__ void __DEFAULT_FN_ATTRS __cpuidex(int __info[4], int __level, int __ecx) { + __asm__("cpuid" : "=a"(__info[0]), "=b"(__info[1]), "=c"(__info[2]), "=d"(__info[3]) : "a"(__level), "c"(__ecx)); +} +#endif + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/arch/arm/constants-arm.h b/app/src/main/cpp/Dobby/source/core/arch/arm/constants-arm.h new file mode 100644 index 0000000..b326d34 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/arm/constants-arm.h @@ -0,0 +1,70 @@ +#ifndef CORE_ARCH_CONSTANTS_ARM_H +#define CORE_ARCH_CONSTANTS_ARM_H + +enum AddrMode { Offset = 0, PreIndex = 1, PostIndex = 2 }; + +enum Condition { + EQ = 0, // equal + NE = 1, // not equal + CS = 2, // carry set/unsigned higher or same + CC = 3, // carry clear/unsigned lower + MI = 4, // minus/negative + PL = 5, // plus/positive or zero + VS = 6, // overflow + VC = 7, // no overflow + HI = 8, // unsigned higher + LS = 9, // unsigned lower or same + GE = 10, // signed greater than or equal + LT = 11, // signed less than + GT = 12, // signed greater than + LE = 13, // signed less than or equal + AL = 14, // always (unconditional) + +}; + +enum Shift { + LSL = 0, // Logical shift left + LSR = 1, // Logical shift right + ASR = 2, // Arithmetic shift right + ROR = 3, // Rotate right +}; + +enum { + B0 = 1 << 0, + B4 = 1 << 4, + B5 = 1 << 5, + B6 = 1 << 6, + B7 = 1 << 7, + B8 = 1 << 8, + B9 = 1 << 9, + B10 = 1 << 10, + B12 = 1 << 12, + B14 = 1 << 14, + B15 = 1 << 15, + B16 = 1 << 16, + B17 = 1 << 17, + B18 = 1 << 18, + B19 = 1 << 19, + B20 = 1 << 20, + B21 = 1 << 21, + B22 = 1 << 22, + B23 = 1 << 23, + B24 = 1 << 24, + B25 = 1 << 25, + B26 = 1 << 26, + B27 = 1 << 27, + B28 = 1 << 28, +}; + +enum InstructionFields { + // Registers. + kRdShift = 12, + kRtShift = 12, + kRmShift = 10, + kRnShift = 16, + + // Condition + kConditionShift = 28, +}; + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/arm/registers-arm.h b/app/src/main/cpp/Dobby/source/core/arch/arm/registers-arm.h new file mode 100644 index 0000000..88b7c2e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/arm/registers-arm.h @@ -0,0 +1,58 @@ +#ifndef ARCH_ARM_REGISTERS +#define ARCH_ARM_REGISTERS + +#include "core/arch/arm/constants-arm.h" +#include "core/arch/Cpu.h" + +namespace zz { +namespace arm { + +#define GENERAL_REGISTERS(V) \ + V(r0) V(r1) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) V(r8) V(r9) V(r10) V(r11) V(r12) V(sp) V(lr) V(pc) + +enum RegisterCode { +#define REGISTER_CODE(R) kRegCode_##R, + GENERAL_REGISTERS(REGISTER_CODE) +#undef REGISTER_CODE + kRegAfterLast +}; + +class Register : public RegisterBase { +public: + explicit constexpr Register(int code) : RegisterBase(code) { + } + + static constexpr Register Create(int code) { + return Register(code); + } + + static constexpr Register R(int code) { + return Register(code); + } + + bool Is(const Register ®) const { + return (reg.reg_code_ == this->reg_code_); + } + + bool IsValid() const { + return (reg_code_ != 0); + } + + int code() const { + return reg_code_; + } + +private: +}; + +typedef Register CPURegister; + +#define DECLARE_REGISTER(R) constexpr Register R = Register::Create(kRegCode_##R); +GENERAL_REGISTERS(DECLARE_REGISTER) +#undef DECLARE_REGISTER + +constexpr Register no_reg = Register::Create(0); + +} // namespace arm +} // namespace zz +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/arm64/constants-arm64.h b/app/src/main/cpp/Dobby/source/core/arch/arm64/constants-arm64.h new file mode 100644 index 0000000..5540e6b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/arm64/constants-arm64.h @@ -0,0 +1,387 @@ +#ifndef CORE_ARCH_CONSTANTS_ARM64_H +#define CORE_ARCH_CONSTANTS_ARM64_H + +#include "common_header.h" + +enum Shift { NO_SHIFT = -1, LSL = 0x0, LSR = 0x1, ASR = 0x2, ROR = 0x3, MSL = 0x4 }; + +enum Extend { NO_EXTEND = -1, UXTB = 0, UXTH = 1, UXTW = 2, UXTX = 3, SXTB = 4, SXTH = 5, SXTW = 6, SXTX = 7 }; + +enum AddrMode { Offset, PreIndex, PostIndex }; + +enum FlagsUpdate { SetFlags = 1, LeaveFlags = 0 }; + +enum InstructionFields { + + // Registers. + kRdShift = 0, + kRdBits = 5, + kRnShift = 5, + kRnBits = 5, + kRaShift = 10, + kRaBits = 5, + kRmShift = 16, + kRmBits = 5, + kRtShift = 0, + kRtBits = 5, + kRt2Shift = 10, + kRt2Bits = 5, + kRsShift = 16, + kRsBits = 5, + +}; + +#define OP(op) op +#define OP_W(op) op##_w +#define OP_X(op) op##_x +#define OP_B(op) op##_b +#define OP_H(op) op##_h +#define OP_S(op) op##_s +#define OP_D(op) op##_d +#define OP_Q(op) op##_q + +#define OPT(op, attribute) op##_##attribute +#define OPT_W(op, attribute) op##_w_##attribute +#define OPT_X(op, attribute) op##_x_##attribute +#define OPT_B(op, attribute) op##_b_##attribute +#define OPT_H(op, attribute) op##_h_##attribute +#define OPT_S(op, attribute) op##_s_##attribute +#define OPT_D(op, attribute) op##_d_##attribute +#define OPT_Q(op, attribute) op##_q_##attribute + +// ===== + +// Exception. +enum ExceptionOp { + ExceptionFixed = 0xD4000000, + ExceptionFMask = 0xFF000000, + ExceptionMask = 0xFFE0001F, + + HLT = ExceptionFixed | 0x00400000, + BRK = ExceptionFixed | 0x00200000, + SVC = ExceptionFixed | 0x00000001, + HVC = ExceptionFixed | 0x00000002, + SMC = ExceptionFixed | 0x00000003, + DCPS1 = ExceptionFixed | 0x00A00001, + DCPS2 = ExceptionFixed | 0x00A00002, + DCPS3 = ExceptionFixed | 0x00A00003 +}; + +// ===== + +// Unconditional branch. +enum UnconditionalBranchOp { + UnconditionalBranchFixed = 0x14000000, + UnconditionalBranchFixedMask = 0x7C000000, + UnconditionalBranchMask = 0xFC000000, + + B = UnconditionalBranchFixed | 0x00000000, + BL = UnconditionalBranchFixed | 0x80000000 +}; + +// ===== + +// Unconditional branch to register. +enum UnconditionalBranchToRegisterOp { + UnconditionalBranchToRegisterFixed = 0xD6000000, + UnconditionalBranchToRegisterFixedMask = 0xFE000000, + UnconditionalBranchToRegisterMask = 0xFFFFFC1F, + + BR = UnconditionalBranchToRegisterFixed | 0x001F0000, + BLR = UnconditionalBranchToRegisterFixed | 0x003F0000, + RET = UnconditionalBranchToRegisterFixed | 0x005F0000 +}; + +// ===== + +enum LoadRegLiteralOp { + LoadRegLiteralFixed = 0x18000000, + LoadRegLiteralFixedMask = 0x3B000000, + LoadRegLiteralMask = 0xFF000000, + +#define LoadRegLiteralSub(opc, V) LoadRegLiteralFixed | LeftShift(opc, 2, 30) | LeftShift(V, 1, 26) + OPT_W(LDR, literal) = LoadRegLiteralSub(0b00, 0), + OPT_X(LDR, literal) = LoadRegLiteralSub(0b01, 0), + OPT(LDRSW, literal) = LoadRegLiteralSub(0b10, 0), + OPT(PRFM, literal) = LoadRegLiteralSub(0b11, 0), + OPT_S(LDR, literal) = LoadRegLiteralSub(0b00, 1), + OPT_D(LDR, literal) = LoadRegLiteralSub(0b01, 1), + OPT_Q(LDR, literal) = LoadRegLiteralSub(0b10, 1), +}; + +// ===== + +// clang-format off +#define LOAD_STORE_OP_LIST(V) \ + V(OP_W(STRB), 0b00, 0, 0b00), \ + V(OP_W(LDRB), 0b00, 0, 0b01), \ + V(OP_X(LDRSB), 0b00, 0, 0b10), \ + V(OP_W(LDRSB), 0b00, 0, 0b11), \ + V(OP_B(STR), 0b00, 1, 0b00), \ + V(OP_B(LDR), 0b00, 1, 0b01), \ + V(OP_Q(STR), 0b00, 1, 0b10), \ + V(OP_Q(LDR), 0b00, 1, 0b11), \ + V(OP_W(STRH), 0b01, 0, 0b00), \ + V(OP_W(LDRH), 0b01, 0, 0b01), \ + V(OP_X(LDRSH), 0b01, 0, 0b10), \ + V(OP_W(LDRSH), 0b01, 0, 0b11), \ + V(OP_H(STR), 0b01, 1, 0b00), \ + V(OP_H(LDR), 0b01, 1, 0b01), \ + V(OP_W(STR), 0b10, 0, 0b00), \ + V(OP_W(LDR), 0b10, 0, 0b01), \ + V(OP(LDRSW), 0b10, 0, 0b10), \ + V(OP_S(STR), 0b10, 1, 0b00), \ + V(OP_S(LDR), 0b10, 1, 0b01), \ + V(OP_X(STR), 0b11, 0, 0b00), \ + V(OP_X(LDR), 0b11, 0, 0b01), \ + V(OP(PRFM), 0b11, 0, 0b10), \ + V(OP_D(STR), 0b11, 1, 0b00), \ + V(OP_D(LDR), 0b11, 1, 0b01), +// clang-format on + +// Load/store +enum LoadStoreOp { +#define LoadStoreOpSub(size, V, opc) LeftShift(size, 2, 30) | LeftShift(V, 1, 26) | LeftShift(opc, 2, 22) +#define LOAD_STORE(opname, size, V, opc) OP(opname) = LoadStoreOpSub(size, V, opc) + LOAD_STORE_OP_LIST(LOAD_STORE) +#undef LOAD_STORE +}; + +// Load/store register offset. +enum LoadStoreRegisterOffsetOp { + LoadStoreRegisterOffsetFixed = 0x38200800, + LoadStoreRegisterOffsetFixedMask = 0x3B200C00, + LoadStoreRegisterOffsetMask = 0xFFE00C00, + +#define LoadStoreRegisterOffsetOpSub(size, V, opc) \ + LoadStoreRegisterOffsetFixed | LeftShift(size, 2, 30) | LeftShift(V, 1, 26) | LeftShift(opc, 2, 22) +#define LOAD_STORE_REGISTER_OFFSET(opname, size, V, opc) \ + OPT(opname, register) = LoadStoreRegisterOffsetOpSub(size, V, opc) + LOAD_STORE_OP_LIST(LOAD_STORE_REGISTER_OFFSET) +#undef LOAD_STORE_REGISTER_OFFSET +}; + +// Load/store register (unscaled immediate) +enum LoadStoreUnscaledOffsetOp { + LoadStoreUnscaledOffsetFixed = 0x38000000, + LoadStoreUnscaledOffsetFixedMask = 0x3B200C00, + LoadStoreUnscaledOffsetMask = 0xFFE00C00, + +#define LoadStoreUnscaledOffsetOpSub(size, V, opc) \ + LoadStoreUnscaledOffsetFixed | LeftShift(size, 2, 30) | LeftShift(V, 1, 26) | LeftShift(opc, 2, 22) +#define LOAD_STORE_UNSCALED(opname, size, V, opc) OPT(opname, unscaled) = LoadStoreUnscaledOffsetOpSub(size, V, opc) + LOAD_STORE_OP_LIST(LOAD_STORE_UNSCALED) +#undef LOAD_STORE_UNSCALED +}; + +// Load/store unsigned offset. +enum LoadStoreUnsignedOffset { + LoadStoreUnsignedOffsetFixed = 0x39000000, + LoadStoreUnsignedOffsetFixedMask = 0x3B000000, + LoadStoreUnsignedOffsetMask = 0xFFC00000, + +#define LoadStoreUnsignedOffsetSub(size, V, opc) \ + LoadStoreUnsignedOffsetFixed | LeftShift(size, 2, 30) | LeftShift(V, 1, 26) | LeftShift(opc, 2, 22) +#define LOAD_STORE_UNSIGNED_OFFSET(opname, size, V, opc) \ + OPT(opname, unsigned) = LoadStoreUnsignedOffsetSub(size, V, opc) + LOAD_STORE_OP_LIST(LOAD_STORE_UNSIGNED_OFFSET) +#undef LOAD_STORE_UNSIGNED_OFFSET +}; + +// ===== + +// clang-format off +#define LOAD_STORE_PAIR_OP_LIST(V) \ + V(OP_W(STP), 0b00, 0, 0), \ + V(OP_W(LDP), 0b00, 0, 1), \ + V(OP_S(STP), 0b00, 1, 0), \ + V(OP_S(LDP), 0b00, 1, 1), \ + V(OP(LDPSW), 0b01, 0, 1), \ + V(OP_D(STP), 0b01, 1, 0), \ + V(OP_D(LDP), 0b01, 1, 1), \ + V(OP_X(STP), 0b10, 0, 0), \ + V(OP_X(LDP), 0b10, 0, 1), \ + V(OP_Q(STP), 0b10, 1, 0), \ + V(OP_Q(LDP), 0b10, 1, 1) +// clang-format on + +enum LoadStorePairOp { +#define LoadStorePairOpSub(opc, V, L) LeftShift(opc, 2, 30) | LeftShift(V, 1, 26) | LeftShift(L, 1, 22) +#define LOAD_STORE_PAIR(opname, opc, V, L) OP(opname) = LoadStorePairOpSub(opc, V, L) + LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR) +#undef LOAD_STORE_PAIR +}; + +enum LoadStorePairOffsetOp { + LoadStorePairOffsetFixed = 0x29000000, + LoadStorePairOffsetFixedMask = 0x3B800000, + LoadStorePairOffsetMask = 0xFFC00000, + +#define LoadStorePairOffsetOpSub(opc, V, L) \ + LoadStorePairOffsetFixed | LeftShift(opc, 2, 30) | LeftShift(V, 1, 26) | LeftShift(L, 1, 22) +#define LOAD_STORE_PAIR_OFFSET(opname, opc, V, L) OPT(opname, offset) = LoadStorePairOffsetOpSub(opc, V, L) + LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_OFFSET) +#undef LOAD_STORE_PAIR_OFFSET +}; + +enum LoadStorePairPostIndexOp { + LoadStorePairPostIndexFixed = 0x28800000, + LoadStorePairPostIndexFixedMask = 0x3B800000, + LoadStorePairPostIndexMask = 0xFFC00000, + +#define LoadStorePairPostOpSub(opc, V, L) \ + LoadStorePairPostIndexFixed | LeftShift(opc, 2, 30) | LeftShift(V, 1, 26) | LeftShift(L, 1, 22) +#define LOAD_STORE_PAIR_POST_INDEX(opname, opc, V, L) OPT(opname, post) = LoadStorePairPostOpSub(opc, V, L) + LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_POST_INDEX) +#undef LOAD_STORE_PAIR_POST_INDEX +}; + +enum LoadStorePairPreIndexOp { + LoadStorePairPreIndexFixed = 0x29800000, + LoadStorePairPreIndexFixedMask = 0x3B800000, + LoadStorePairPreIndexMask = 0xFFC00000, + +#define LoadStorePairPreOpSub(opc, V, L) \ + LoadStorePairPreIndexFixed | LeftShift(opc, 2, 30) | LeftShift(V, 1, 26) | LeftShift(L, 1, 22) +#define LOAD_STORE_PAIR_PRE_INDEX(opname, opc, V, L) OPT(opname, pre) = LoadStorePairPreOpSub(opc, V, L) + LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_PRE_INDEX) +#undef LOAD_STORE_PAIR_PRE_INDEX +}; + +// ===== + +// Generic fields. +enum GenericInstrField { SixtyFourBits = 0x80000000, ThirtyTwoBits = 0x00000000, FP32 = 0x00000000, FP64 = 0x00400000 }; + +// Generic utils +// #define sf(rd) (rd.Is64Bits() ? SixtyFourBits : ThirtyTwoBits) + +// ===== + +// Move wide immediate. +enum MoveWideImmediateOp { + MoveWideImmediateFixed = 0x12800000, + MoveWideImmediateFixedMask = 0x1F800000, + MoveWideImmediateMask = 0xFF800000, + + OP(MOVN) = 0x00000000, + OP(MOVZ) = 0x40000000, + OP(MOVK) = 0x60000000, + +#define MoveWideImmediateOpSub(sf, opc) MoveWideImmediateFixed | LeftShift(sf, 1, 31) | LeftShift(opc, 2, 29) + OP_W(MOVN) = MoveWideImmediateFixed | MOVN, + OP_X(MOVN) = MoveWideImmediateFixed | MOVN | SixtyFourBits, + OP_W(MOVZ) = MoveWideImmediateFixed | MOVZ, + OP_X(MOVZ) = MoveWideImmediateFixed | MOVZ | SixtyFourBits, + OP_W(MOVK) = MoveWideImmediateFixed | MOVK, + OP_X(MOVK) = MoveWideImmediateFixed | MOVK | SixtyFourBits +}; + +// ===== + +enum AddSubImmediateOp { + AddSubImmediateFixed = 0x11000000, + AddSubImmediateFixedMask = 0x1F000000, + AddSubImmediateMask = 0xFF000000, + +#define AddSubImmediateOpSub(sf, op, S) \ + AddSubImmediateFixed | LeftShift(sf, 1, 31) | LeftShift(op, 1, 30) | LeftShift(S, 1, 29) + OPT_W(ADD, imm) = AddSubImmediateOpSub(0, 0, 0), + OPT_W(ADDS, imm) = AddSubImmediateOpSub(0, 0, 1), + OPT_W(SUB, imm) = AddSubImmediateOpSub(0, 1, 0), + OPT_W(SUBS, imm) = AddSubImmediateOpSub(0, 1, 1), + OPT_X(ADD, imm) = AddSubImmediateOpSub(1, 0, 0), + OPT_X(ADDS, imm) = AddSubImmediateOpSub(1, 0, 1), + OPT_X(SUB, imm) = AddSubImmediateOpSub(1, 1, 0), + OPT_X(SUBS, imm) = AddSubImmediateOpSub(1, 1, 1) +}; + +enum AddSubShiftedOp { + AddSubShiftedFixed = 0x0B000000, + AddSubShiftedFixedMask = 0x1F200000, + AddSubShiftedMask = 0xFF200000, + +#define AddSubShiftedOpSub(sf, op, S) \ + AddSubShiftedFixed | LeftShift(sf, 1, 31) | LeftShift(op, 1, 30) | LeftShift(S, 1, 29) + OPT_W(ADD, shift) = AddSubShiftedOpSub(0, 0, 0), + OPT_W(ADDS, shift) = AddSubShiftedOpSub(0, 0, 1), + OPT_W(SUB, shift) = AddSubShiftedOpSub(0, 1, 0), + OPT_W(SUBS, shift) = AddSubShiftedOpSub(0, 1, 1), + OPT_X(ADD, shift) = AddSubShiftedOpSub(1, 0, 0), + OPT_X(ADDS, shift) = AddSubShiftedOpSub(1, 0, 1), + OPT_X(SUB, shift) = AddSubShiftedOpSub(1, 1, 0), + OPT_X(SUBS, shift) = AddSubShiftedOpSub(1, 1, 1) +}; + +enum AddSubExtendedOp { + AddSubExtendedFixed = 0x0B200000, + AddSubExtendedFixedMask = 0x1F200000, + AddSubExtendedMask = 0xFFE00000, + +#define AddSubExtendedOpSub(sf, op, S) \ + AddSubExtendedFixed | LeftShift(sf, 1, 31) | LeftShift(op, 1, 30) | LeftShift(S, 1, 29) + OPT_W(ADD, extend) = AddSubExtendedOpSub(0, 0, 0), + OPT_W(ADDS, extend) = AddSubExtendedOpSub(0, 0, 1), + OPT_W(SUB, extend) = AddSubExtendedOpSub(0, 1, 0), + OPT_W(SUBS, extend) = AddSubExtendedOpSub(0, 1, 1), + OPT_X(ADD, extend) = AddSubExtendedOpSub(1, 0, 0), + OPT_X(ADDS, extend) = AddSubExtendedOpSub(1, 0, 1), + OPT_X(SUB, extend) = AddSubExtendedOpSub(1, 1, 0), + OPT_X(SUBS, extend) = AddSubExtendedOpSub(1, 1, 1) +}; + +// ===== + +// Logical (immediate and shifted register). +enum LogicalOp { + LogicalOpMask = 0x60200000, + NOT = 0x00200000, + AND = 0x00000000, + BIC = AND | NOT, + ORR = 0x20000000, + ORN = ORR | NOT, + EOR = 0x40000000, + EON = EOR | NOT, + ANDS = 0x60000000, + BICS = ANDS | NOT +}; + +// Logical immediate. +enum LogicalImmediateOp { + LogicalImmediateFixed = 0x12000000, + LogicalImmediateFixedMask = 0x1F800000, + LogicalImmediateMask = 0xFF800000, + +#define W_X_OP(opname, combine_fields) \ + OPT_W(opname, imm) = LogicalImmediateFixed | combine_fields | ThirtyTwoBits, \ + OPT_X(opname, imm) = LogicalImmediateFixed | combine_fields | SixtyFourBits +#define W_X_OP_LIST(V) V(AND, AND), V(ORR, ORR), V(EOR, EOR), V(ANDS, ANDS) +#undef W_X_OP +#undef W_X_OP_LIST +}; + +// Logical shifted register. +enum LogicalShiftedOp { + LogicalShiftedFixed = 0x0A000000, + LogicalShiftedFixedMask = 0x1F000000, + LogicalShiftedMask = 0xFF200000, + +#define W_X_OP(opname, combine_fields) \ + OPT_W(opname, shift) = LogicalShiftedFixed | combine_fields | ThirtyTwoBits, \ + OPT_X(opname, shift) = LogicalShiftedFixed | combine_fields | SixtyFourBits +#define W_X_OP_LIST(V) \ + V(AND, AND), V(BIC, BIC), V(ORR, ORR), V(ORN, ORN), V(EOR, EOR), V(EON, EON), V(ANDS, ANDS), V(BICS, BICS) +#undef W_X_OP +#undef W_X_OP_LIST +}; + +// PC relative addressing. +enum PCRelAddressingOp { + PCRelAddressingFixed = 0x10000000, + PCRelAddressingFixedMask = 0x1F000000, + PCRelAddressingMask = 0x9F000000, + ADR = PCRelAddressingFixed | 0x00000000, + ADRP = PCRelAddressingFixed | 0x80000000 +}; + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/arch/arm64/registers-arm64.h b/app/src/main/cpp/Dobby/source/core/arch/arm64/registers-arm64.h new file mode 100644 index 0000000..84a6d6b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/arm64/registers-arm64.h @@ -0,0 +1,142 @@ +#ifndef ARCH_ARM64_REGISTERS +#define ARCH_ARM64_REGISTERS + +#include "core/arch/arm64/constants-arm64.h" +#include "core/arch/Cpu.h" + +namespace zz { +namespace arm64 { + +class CPURegister : RegisterBase { +public: + enum RegisterType { + kRegister_32, + kRegister_W = kRegister_32, + kRegister_64, + kRegister_X = kRegister_64, + kRegister, + + kVRegister, + kSIMD_FP_Register_8, + kSIMD_FP_Register_B = kSIMD_FP_Register_8, + kSIMD_FP_Register_16, + kSIMD_FP_Register_H = kSIMD_FP_Register_16, + kSIMD_FP_Register_32, + kSIMD_FP_Register_S = kSIMD_FP_Register_32, + kSIMD_FP_Register_64, + kSIMD_FP_Register_D = kSIMD_FP_Register_64, + kSIMD_FP_Register_128, + kSIMD_FP_Register_Q = kSIMD_FP_Register_128, + + kInvalid + }; + + constexpr CPURegister(int code, int size, RegisterType type) : RegisterBase(code), reg_size_(size), reg_type_(type) { + } + + static constexpr CPURegister Create(int code, int size, RegisterType type) { + return CPURegister(code, size, type); + } + + // ===== + + static constexpr CPURegister X(int code) { + return CPURegister(code, 64, kRegister_64); + } + + static constexpr CPURegister W(int code) { + return CPURegister(code, 32, kRegister_32); + } + + static constexpr CPURegister Q(int code) { + return CPURegister(code, 128, kSIMD_FP_Register_128); + } + + static constexpr CPURegister InvalidRegister() { + return CPURegister(0, 0, kInvalid); + } + + // ===== + + bool Is(const CPURegister ®) const { + return (reg.reg_code_ == this->reg_code_); + } + + bool Is64Bits() const { + return reg_size_ == 64; + } + + bool IsRegister() const { + return reg_type_ < kRegister; + } + + bool IsVRegister() const { + return reg_type_ > kVRegister; + } + + // ===== + + RegisterType type() const { + return reg_type_; + } + + int32_t code() const { + return reg_code_; + }; + +private: + RegisterType reg_type_; + int reg_size_; +}; + +typedef CPURegister Register; +typedef CPURegister VRegister; + +// clang-format off +#define GENERAL_REGISTER_CODE_LIST(R) \ + R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ + R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ + R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ + R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) + +#define DEFINE_REGISTER(register_class, name, ...) constexpr register_class name = register_class::Create(__VA_ARGS__) + +#define DEFINE_REGISTERS(N) \ + DEFINE_REGISTER(Register, w##N, N, 32, CPURegister::kRegister_32); \ + DEFINE_REGISTER(Register, x##N, N, 64, CPURegister::kRegister_64); + GENERAL_REGISTER_CODE_LIST(DEFINE_REGISTERS) +#undef DEFINE_REGISTERS + +#define DEFINE_VREGISTERS(N) \ + DEFINE_REGISTER(VRegister, b##N, N, 8, CPURegister::kSIMD_FP_Register_8); \ + DEFINE_REGISTER(VRegister, h##N, N, 16, CPURegister::kSIMD_FP_Register_16); \ + DEFINE_REGISTER(VRegister, s##N, N, 32, CPURegister::kSIMD_FP_Register_32); \ + DEFINE_REGISTER(VRegister, d##N, N, 64, CPURegister::kSIMD_FP_Register_64); \ + DEFINE_REGISTER(VRegister, q##N, N, 128, CPURegister::kSIMD_FP_Register_128); \ +GENERAL_REGISTER_CODE_LIST(DEFINE_VREGISTERS) +#undef DEFINE_VREGISTERS + +#undef DEFINE_REGISTER +// clang-format on + +// ===== + +constexpr Register wzr = w31; +constexpr Register xzr = x31; + +constexpr Register SP = x31; +constexpr Register wSP = w31; +constexpr Register FP = x29; +constexpr Register wFP = w29; +constexpr Register LR = x30; +constexpr Register wLR = w30; + +} // namespace arm64 +} // namespace zz + +#define W(code) CPURegister::W(code) +#define X(code) CPURegister::X(code) +#define Q(code) CPURegister::Q(code) +#define InvalidRegister CPURegister::InvalidRegister() + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/arch/x64/constants-x64.h b/app/src/main/cpp/Dobby/source/core/arch/x64/constants-x64.h new file mode 100644 index 0000000..d72f44f --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/x64/constants-x64.h @@ -0,0 +1,21 @@ +#ifndef CORE_ARCH_CONSTANTS_X64_H +#define CORE_ARCH_CONSTANTS_X64_H + +namespace zz { +namespace x64 { + +enum ScaleFactor { + TIMES_1 = 0, + TIMES_2 = 1, + TIMES_4 = 2, + TIMES_8 = 3, + TIMES_16 = 4, + TIMES_HALF_WORD_SIZE = sizeof(void *) / 2 - 1 +}; + +enum RexBits { REX_NONE = 0, REX_B = 1 << 0, REX_X = 1 << 1, REX_R = 1 << 2, REX_W = 1 << 3, REX_PREFIX = 1 << 6 }; + +} // namespace x64 +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/x64/registers-x64.h b/app/src/main/cpp/Dobby/source/core/arch/x64/registers-x64.h new file mode 100644 index 0000000..4c7c612 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/x64/registers-x64.h @@ -0,0 +1,244 @@ +#ifndef ARCH_X64_REGISTERS +#define ARCH_X64_REGISTERS + +#include "core/arch/x64/constants-x64.h" +#include "core/arch/Cpu.h" + +namespace zz { +namespace x64 { + +#define GENERAL_REGISTERS(V) \ + V(rax) \ + V(rcx) \ + V(rdx) \ + V(rbx) \ + V(rsp) \ + V(rbp) \ + V(rsi) \ + V(rdi) \ + V(r8) \ + V(r9) \ + V(r10) \ + V(r11) \ + V(r12) \ + V(r13) \ + V(r14) \ + V(r15) + +#define GENERAL_32_REGISTERS(V) \ + V(eax) \ + V(ecx) \ + V(edx) \ + V(ebx) \ + V(esp) \ + V(ebp) \ + V(esi) \ + V(edi) + +#define GENERAL_16_REGISTERS(V) \ + V(ax) \ + V(cx) \ + V(dx) \ + V(bx) \ + V(sp) \ + V(bp) \ + V(si) \ + V(di) + +#define GENERAL_8H_REGISTERS(V) \ + V(ah) \ + V(ch) \ + V(dh) \ + V(bh) + +#define GENERAL_8L_REGISTERS(V) \ + V(al) \ + V(cl) \ + V(dl) \ + V(bl) + +// clang-format off +enum RegisterCode { +#define REGISTER_CODE(R) kRegCode_##R, + kRegisterCodeStart8L = -1, + GENERAL_8L_REGISTERS(REGISTER_CODE) + kRegisterCodeStart8H = -1, + GENERAL_8H_REGISTERS(REGISTER_CODE) + kRegisterCodeStart16 = -1, + GENERAL_16_REGISTERS(REGISTER_CODE) + kRegisterCodeStart32 = -1, + GENERAL_32_REGISTERS(REGISTER_CODE) + kRegisterCodeStart64 = -1, + GENERAL_REGISTERS(REGISTER_CODE) +#undef REGISTER_CODE + kRegAfterLast +}; +// clang-format on + +class CPURegister : public RegisterBase { +public: + enum RegisterType { kDefault, kInvalid }; + + constexpr CPURegister(int code, int size, RegisterType type) : RegisterBase(code), reg_size_(size), reg_type_(type) { + } + + static constexpr CPURegister Create(int code, int size, RegisterType type) { + return CPURegister(code, size, type); + } + + static constexpr CPURegister from_code(int code) { + return CPURegister(code, 0, kDefault); + } + + static constexpr CPURegister InvalidRegister() { + return CPURegister(0, 0, kInvalid); + } + + bool Is64Bits() const { + return reg_size_ == 64; + } + + RegisterType type() const { + return reg_type_; + } + +public: + bool is_byte_register() const { + return reg_code_ <= 3; + } + + // Return the high bit of the register code as a 0 or 1. Used often + // when constructing the REX prefix byte. + int high_bit() const { + return reg_code_ >> 3; + } + + // Return the 3 low bits of the register code. Used when encoding registers + // in modR/M, SIB, and opcode bytes. + int low_bits() const { + return reg_code_ & 0x7; + } + + int size() { + return reg_size_; + } + +private: + RegisterType reg_type_; + int reg_size_; +}; + +typedef CPURegister Register; + +#define DECLARE_REGISTER(R) constexpr Register R = Register::Create(kRegCode_##R, 64, CPURegister::kDefault); +GENERAL_REGISTERS(DECLARE_REGISTER) +#undef DECLARE_REGISTER + +#define DECLARE_REGISTER(R) constexpr Register R = Register::Create(kRegCode_##R, 8, CPURegister::kDefault); +GENERAL_8H_REGISTERS(DECLARE_REGISTER) +#undef DECLARE_REGISTER + +#define DECLARE_REGISTER(R) constexpr Register R = Register::Create(kRegCode_##R, 8, CPURegister::kDefault); +GENERAL_8L_REGISTERS(DECLARE_REGISTER) +#undef DECLARE_REGISTER + +#define DECLARE_REGISTER(R) constexpr Register R = Register::Create(kRegCode_##R, 16, CPURegister::kDefault); +GENERAL_16_REGISTERS(DECLARE_REGISTER) +#undef DECLARE_REGISTER + +#define DECLARE_REGISTER(R) constexpr Register R = Register::Create(kRegCode_##R, 32, CPURegister::kDefault); +GENERAL_32_REGISTERS(DECLARE_REGISTER) +#undef DECLARE_REGISTER + +#ifdef _WIN64 +// Windows calling convention +constexpr Register arg_reg_1 = rcx; +constexpr Register arg_reg_2 = rdx; +constexpr Register arg_reg_3 = r8; +constexpr Register arg_reg_4 = r9; +#else +// AMD64 calling convention +constexpr Register arg_reg_1 = rdi; +constexpr Register arg_reg_2 = rsi; +constexpr Register arg_reg_3 = rdx; +constexpr Register arg_reg_4 = rcx; +#endif // _WIN64 + +#define DOUBLE_REGISTERS(V) \ + V(xmm0) \ + V(xmm1) \ + V(xmm2) \ + V(xmm3) \ + V(xmm4) \ + V(xmm5) \ + V(xmm6) \ + V(xmm7) \ + V(xmm8) \ + V(xmm9) \ + V(xmm10) \ + V(xmm11) \ + V(xmm12) \ + V(xmm13) \ + V(xmm14) \ + V(xmm15) + +#define FLOAT_REGISTERS DOUBLE_REGISTERS +#define SIMD128_REGISTERS DOUBLE_REGISTERS + +constexpr bool kPadArguments = false; +constexpr bool kSimpleFPAliasing = true; +constexpr bool kSimdMaskRegisters = false; + +enum DoubleRegisterCode { +#define REGISTER_CODE(R) kDoubleCode_##R, + DOUBLE_REGISTERS(REGISTER_CODE) +#undef REGISTER_CODE + kDoubleAfterLast +}; + +class XMMRegister : public RegisterBase { +public: + enum RegisterType { kInvalid }; + + constexpr XMMRegister(int code) : RegisterBase(code) { + } + + static constexpr XMMRegister Create(int code) { + return XMMRegister(code); + } + + static constexpr XMMRegister InvalidRegister() { + return XMMRegister(0); + } + +public: + // Return the high bit of the register code as a 0 or 1. Used often + // when constructing the REX prefix byte. + int high_bit() const { + return reg_code_ >> 3; + } + // Return the 3 low bits of the register code. Used when encoding registers + // in modR/M, SIB, and opcode bytes. + int low_bits() const { + return reg_code_ & 0x7; + } + +private: +}; + +typedef XMMRegister FloatRegister; + +typedef XMMRegister DoubleRegister; + +typedef XMMRegister Simd128Register; + +typedef XMMRegister FPURegister; + +#define DECLARE_REGISTER(R) constexpr DoubleRegister R = DoubleRegister::Create(kDoubleCode_##R); +DOUBLE_REGISTERS(DECLARE_REGISTER) +#undef DECLARE_REGISTER + +} // namespace x64 +} // namespace zz + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/arch/x86/constants-x86.h b/app/src/main/cpp/Dobby/source/core/arch/x86/constants-x86.h new file mode 100644 index 0000000..a243a76 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/x86/constants-x86.h @@ -0,0 +1,19 @@ +#ifndef CORE_ARCH_CONSTANTS_X86_H +#define CORE_ARCH_CONSTANTS_X86_H + +namespace zz { +namespace x86 { + +enum ScaleFactor { + TIMES_1 = 0, + TIMES_2 = 1, + TIMES_4 = 2, + TIMES_8 = 3, + TIMES_16 = 4, + TIMES_HALF_WORD_SIZE = sizeof(void *) / 2 - 1 +}; + +} // namespace x86 +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/x86/cpu-x86.cc b/app/src/main/cpp/Dobby/source/core/arch/x86/cpu-x86.cc new file mode 100644 index 0000000..bd29a56 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/x86/cpu-x86.cc @@ -0,0 +1,98 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) + +#include "cpu-x86.h" + +X86CpuInfo::X86CpuInfo() { + icache_line_size_ = 0; + dcache_line_size_ = 0; + has_fpu_ = false; + has_cmov_ = false; + has_sahf_ = false; + has_mmx_ = false; + has_sse_ = false; + has_sse2_ = false; + has_sse3_ = false; + has_ssse3_ = false; + has_sse41_ = false; + + has_sse42_ = false; + has_osxsave_ = false; + has_avx_ = false; + has_fma3_ = false; + has_bmi1_ = false; + has_bmi2_ = false; + has_lzcnt_ = false; + has_popcnt_ = false; + is_atom_ = false; + + memcpy(vendor_, (void *)"Unknown", 8); +#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64 + int cpu_info[4]; + __cpuid(cpu_info, 0); + unsigned num_ids = cpu_info[0]; + std::swap(cpu_info[2], cpu_info[3]); + _memcpy(vendor_, cpu_info + 1, 12); + vendor_[12] = '\0'; + + // Interpret CPU feature information. + if (num_ids > 0) { + __cpuid(cpu_info, 1); + stepping_ = cpu_info[0] & 0xF; + model_ = ((cpu_info[0] >> 4) & 0xF) + ((cpu_info[0] >> 12) & 0xF0); + family_ = (cpu_info[0] >> 8) & 0xF; + type_ = (cpu_info[0] >> 12) & 0x3; + ext_model_ = (cpu_info[0] >> 16) & 0xF; + ext_family_ = (cpu_info[0] >> 20) & 0xFF; + has_fpu_ = (cpu_info[3] & 0x00000001) != 0; + has_cmov_ = (cpu_info[3] & 0x00008000) != 0; + has_mmx_ = (cpu_info[3] & 0x00800000) != 0; + has_sse_ = (cpu_info[3] & 0x02000000) != 0; + has_sse2_ = (cpu_info[3] & 0x04000000) != 0; + has_sse3_ = (cpu_info[2] & 0x00000001) != 0; + has_ssse3_ = (cpu_info[2] & 0x00000200) != 0; + has_sse41_ = (cpu_info[2] & 0x00080000) != 0; + has_sse42_ = (cpu_info[2] & 0x00100000) != 0; + has_popcnt_ = (cpu_info[2] & 0x00800000) != 0; + has_osxsave_ = (cpu_info[2] & 0x08000000) != 0; + has_avx_ = (cpu_info[2] & 0x10000000) != 0; + has_fma3_ = (cpu_info[2] & 0x00001000) != 0; + if (family_ == 0x6) { + switch (model_) { + case 0x1C: // SLT + case 0x26: + case 0x36: + case 0x27: + case 0x35: + case 0x37: // SLM + case 0x4A: + case 0x4D: + case 0x4C: // AMT + case 0x6E: + is_atom_ = true; + } + } + } + + // There are separate feature flags for VEX-encoded GPR instructions. + if (num_ids >= 7) { + __cpuid(cpu_info, 7); + has_bmi1_ = (cpu_info[1] & 0x00000008) != 0; + has_bmi2_ = (cpu_info[1] & 0x00000100) != 0; + } + + // Query extended IDs. + __cpuid(cpu_info, 0x80000000); + unsigned num_ext_ids = cpu_info[0]; + + // Interpret extended CPU feature information. + if (num_ext_ids > 0x80000000) { + __cpuid(cpu_info, 0x80000001); + has_lzcnt_ = (cpu_info[2] & 0x00000020) != 0; + // SAHF must be probed in long mode. + has_sahf_ = (cpu_info[2] & 0x00000001) != 0; + } +#endif +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/x86/cpu-x86.h b/app/src/main/cpp/Dobby/source/core/arch/x86/cpu-x86.h new file mode 100644 index 0000000..68fd62c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/x86/cpu-x86.h @@ -0,0 +1,120 @@ +#ifndef CORE_ARCH_CPU_X86_H +#define CORE_ARCH_CPU_X86_H + +#include "core/arch/Cpu.h" + +class X86CpuInfo { + +public: + X86CpuInfo(); + +public: + // General features + bool has_fpu() const { + return has_fpu_; + } + int icache_line_size() const { + return icache_line_size_; + } + int dcache_line_size() const { + return dcache_line_size_; + } + + static const int UNKNOWN_CACHE_LINE_SIZE = 0; + + // x86 features + bool has_cmov() const { + return has_cmov_; + } + bool has_sahf() const { + return has_sahf_; + } + bool has_mmx() const { + return has_mmx_; + } + bool has_sse() const { + return has_sse_; + } + bool has_sse2() const { + return has_sse2_; + } + bool has_sse3() const { + return has_sse3_; + } + bool has_ssse3() const { + return has_ssse3_; + } + bool has_sse41() const { + return has_sse41_; + } + bool has_sse42() const { + return has_sse42_; + } + bool has_osxsave() const { + return has_osxsave_; + } + bool has_avx() const { + return has_avx_; + } + bool has_fma3() const { + return has_fma3_; + } + bool has_bmi1() const { + return has_bmi1_; + } + bool has_bmi2() const { + return has_bmi2_; + } + bool has_lzcnt() const { + return has_lzcnt_; + } + bool has_popcnt() const { + return has_popcnt_; + } + bool is_atom() const { + return is_atom_; + } + +private: + char vendor_[13]; + + // General features + int icache_line_size_; + int dcache_line_size_; + bool has_fpu_; + + // x86 features + bool has_cmov_; + bool has_sahf_; + bool has_mmx_; + bool has_sse_; + bool has_sse2_; + bool has_sse3_; + bool has_ssse3_; + bool has_sse41_; + bool has_sse42_; + bool has_osxsave_; + bool has_avx_; + bool has_fma3_; + bool has_bmi1_; + bool has_bmi2_; + bool has_lzcnt_; + bool has_popcnt_; + bool is_atom_; +}; + +class X86CpuFeatures : public CpuFeatures { +public: + static bool sse2_supported() { + return X86CpuInfo().has_sse2(); + } + static bool sse4_1_supported() { + return X86CpuInfo().has_sse41(); + } + +private: + static bool sse2_supported_; + static bool sse4_1_supported_; +}; + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/arch/x86/registers-x86.h b/app/src/main/cpp/Dobby/source/core/arch/x86/registers-x86.h new file mode 100644 index 0000000..65b06b2 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/arch/x86/registers-x86.h @@ -0,0 +1,124 @@ +#ifndef ARCH_IA32_REGISTERS +#define ARCH_IA32_REGISTERS + +#include "core/arch/x86/constants-x86.h" +#include "core/arch/Cpu.h" + +namespace zz { +namespace x86 { + +#define GENERAL_REGISTERS(V) \ + V(eax) \ + V(ecx) \ + V(edx) \ + V(ebx) \ + V(esp) \ + V(ebp) \ + V(esi) \ + V(edi) + +enum RegisterCode { +#define REGISTER_CODE(R) kRegCode_##R, + GENERAL_REGISTERS(REGISTER_CODE) +#undef REGISTER_CODE + kRegAfterLast +}; + +class CPURegister : public RegisterBase { +public: + enum RegisterType { kDefault, kInvalid }; + + constexpr CPURegister(int code, int size, RegisterType type) : RegisterBase(code), reg_size_(size), reg_type_(type) { + } + + static constexpr CPURegister Create(int code, int size, RegisterType type) { + return CPURegister(code, size, type); + } + + static constexpr CPURegister from_code(int code) { + return CPURegister(code, 0, kDefault); + } + + static constexpr CPURegister InvalidRegister() { + return CPURegister(0, 0, kInvalid); + } + + RegisterType type() const { + return reg_type_; + } + +public: + bool is_byte_register() const { + return reg_code_ <= 3; + } + + int size() { + return reg_size_; + } + +private: + RegisterType reg_type_; + int reg_size_; +}; + +typedef CPURegister Register; + +#define DEFINE_REGISTER(R) constexpr Register R = Register::Create(kRegCode_##R, 32, CPURegister::kDefault); +GENERAL_REGISTERS(DEFINE_REGISTER) +#undef DEFINE_REGISTER + +#define DOUBLE_REGISTERS(V) \ + V(xmm0) \ + V(xmm1) \ + V(xmm2) \ + V(xmm3) \ + V(xmm4) \ + V(xmm5) \ + V(xmm6) \ + V(xmm7) + +#define FLOAT_REGISTERS DOUBLE_REGISTERS +#define SIMD128_REGISTERS DOUBLE_REGISTERS + +constexpr bool kPadArguments = false; +constexpr bool kSimpleFPAliasing = true; +constexpr bool kSimdMaskRegisters = false; + +enum DoubleRegisterCode { +#define REGISTER_CODE(R) kDoubleCode_##R, + DOUBLE_REGISTERS(REGISTER_CODE) +#undef REGISTER_CODE + kDoubleAfterLast +}; + +class XMMRegister : public RegisterBase { +public: + enum RegisterType { kInvalid }; + + constexpr XMMRegister(int code) : RegisterBase(code) { + } + + static constexpr XMMRegister Create(int code) { + return XMMRegister(code); + } + + static constexpr XMMRegister InvalidRegister() { + return XMMRegister(0); + } + +private: +}; + +typedef XMMRegister FloatRegister; +typedef XMMRegister DoubleRegister; +typedef XMMRegister Simd128Register; +typedef XMMRegister FPURegister; + +#define DEFINE_REGISTER(R) constexpr DoubleRegister R = DoubleRegister::Create(kDoubleCode_##R); +DOUBLE_REGISTERS(DEFINE_REGISTER) +#undef DEFINE_REGISTER + +} // namespace x86 +} // namespace zz + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/assembler/AssemblerPseudoLabel.h b/app/src/main/cpp/Dobby/source/core/assembler/AssemblerPseudoLabel.h new file mode 100644 index 0000000..362d1e2 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/AssemblerPseudoLabel.h @@ -0,0 +1,94 @@ +#pragma once + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +class Label { +public: + Label(addr_t addr) : pos_(addr) { + } + +protected: + addr_t pos_; +}; + +class AssemblerPseudoLabel : public Label { +public: + typedef struct { + int type_; + vmaddr_t vmaddr_; + off_t offset_; + } ref_label_inst_t; + +public: + AssemblerPseudoLabel() : AssemblerPseudoLabel(0) { + } + + AssemblerPseudoLabel(vmaddr_t addr) : Label(addr) { + ref_label_insts_.reserve(4); + + pos_ = addr; + relocated_pos_ = 0; + } + + ~AssemblerPseudoLabel(void) { + } + + void link_confused_instructions(CodeBufferBase *buffer); + + bool has_confused_instructions() { + return ref_label_insts_.size(); + } + + void link_confused_instructions(); + + void link_to(int type, vmaddr_t inst_vmaddr, off_t offset) { + ref_label_inst_t inst; + inst.type_ = type; + inst.vmaddr_ = inst_vmaddr; + inst.offset_ = offset; + ref_label_insts_.push_back(inst); + } + +private: + addr_t relocated_pos_; + +public: + addr_t relocated_pos() { + return relocated_pos_; + }; + + void bind_to(vmaddr_t addr) { + relocated_pos_ = addr; + } + + void relocate_to(vmaddr_t addr) { + bind_to(addr); + } + +protected: + std::vector ref_label_insts_; +}; + +// --- + +struct RelocLabel : public AssemblerPseudoLabel { +public: + RelocLabel() : AssemblerPseudoLabel(0) { + } + + template RelocLabel(T value) : AssemblerPseudoLabel(0) { + *(T *)data_ = value; + data_size_ = sizeof(value); + } + + template T data() { + return *(T *)data_; + } + + template void fixup_data(T value) { + *(T *)data_ = value; + } + + uint8_t data_[8]; + int data_size_; +}; \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-arch.h b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arch.h new file mode 100644 index 0000000..23ae9c3 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arch.h @@ -0,0 +1,28 @@ +#ifndef CORE_ASSEMBLER_ARCH_H +#define CORE_ASSEMBLER_ARCH_H + +#include "src/assembler.h" + +#if 0 +#if TARGET_ARCH_IA32 +#include "src/ia32/assembler-ia32.h" +#elif TARGET_ARCH_X64 +#include "src/x64/assembler-x64.h" +#elif TARGET_ARCH_ARM64 +#include "src/arm64/assembler-arm64.h" +#elif TARGET_ARCH_ARM +#include "src/arm/assembler-arm.h" +#elif TARGET_ARCH_PPC +#include "src/ppc/assembler-ppc.h" +#elif TARGET_ARCH_MIPS +#include "src/mips/assembler-mips.h" +#elif TARGET_ARCH_MIPS64 +#include "src/mips64/assembler-mips64.h" +#elif TARGET_ARCH_S390 +#include "src/s390/assembler-s390.h" +#else +#error Unknown architecture. +#endif +#endif + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm.cc b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm.cc new file mode 100644 index 0000000..56aaab5 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm.cc @@ -0,0 +1,41 @@ +#include "platform_macro.h" +#if TARGET_ARCH_ARM + +#include "core/assembler/assembler-arm.h" + +void AssemblerPseudoLabel::link_confused_instructions(CodeBufferBase *buffer) { + CodeBuffer *_buffer = (CodeBuffer *)buffer; + + for (auto &ref_label_inst : ref_label_insts_) { + arm_inst_t inst = _buffer->LoadARMInst(ref_label_inst.offset_); + if (ref_label_inst.type_ == kLdrLiteral) { + int64_t pc = ref_label_inst.offset_ + ARM_PC_OFFSET; + assert(pc % 4 == 0); + int32_t imm12 = relocated_pos() - pc; + if (imm12 > 0) { + set_bit(inst, 23, 1); + } else { + set_bit(inst, 23, 0); + imm12 = -imm12; + } + set_bits(inst, 0, 11, imm12); + } + _buffer->RewriteARMInst(ref_label_inst.offset_, inst); + } +} + +namespace zz { +namespace arm { + +void Assembler::EmitARMInst(arm_inst_t instr) { + buffer_->EmitARMInst(instr); +} + +void Assembler::EmitAddress(uint32_t value) { + buffer_->Emit32(value); +} + +} // namespace arm +} // namespace zz + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm.h b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm.h new file mode 100644 index 0000000..af181ac --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm.h @@ -0,0 +1,357 @@ +#ifndef CORE_ASSEMBLER_ARM_H +#define CORE_ASSEMBLER_ARM_H + +#include "common_header.h" + +#include "core/arch/arm/constants-arm.h" +#include "core/arch/arm/registers-arm.h" +#include "core/assembler/assembler.h" + +#include "MemoryAllocator/CodeBuffer/code_buffer_arm.h" + +enum ref_label_type_t { kLdrLiteral }; + +namespace zz { +namespace arm { + +// ARM design had a 3-stage pipeline (fetch-decode-execute) +#define ARM_PC_OFFSET 8 +#define Thumb_PC_OFFSET 4 + +// define instruction length +#define ARM_INST_LEN 4 +#define Thumb1_INST_LEN 2 +#define Thumb2_INST_LEN 4 + +// Thumb instructions address is odd +#define THUMB_ADDRESS_FLAG 1 + +constexpr Register TMP_REG_0 = r12; + +constexpr Register VOLATILE_REGISTER = r12; + +#define Rd(rd) (rd.code() << kRdShift) +#define Rt(rt) (rt.code() << kRtShift) +#define Rn(rn) (rn.code() << kRnShift) +#define Rm(rm) (rm.code() << kRmShift) + +// --- + +class Operand { + friend class OpEncode; + +public: + Operand(int immediate) : imm_(immediate), rm_(no_reg), shift_(LSL), shift_imm_(0), rs_(no_reg) { + } + + Operand(Register rm) : imm_(0), rm_(rm), shift_(LSL), shift_imm_(0), rs_(no_reg) { + } + + Operand(Register rm, Shift shift, uint32_t shift_imm) + : imm_(0), rm_(rm), shift_(shift), shift_imm_(shift_imm), rs_(no_reg) { + } + + Operand(Register rm, Shift shift, Register rs) : imm_(0), rm_(rm), shift_(shift), shift_imm_(0), rs_(rs) { + } + +public: + int GetImmediate() const { + return imm_; + } + +private: + Register rm_; + Register rs_; + + Shift shift_; + int shift_imm_; + + int imm_; + +private: + friend class EncodeUtility; +}; + +// --- + +class MemOperand { + friend class OpEncode; + +public: + MemOperand(Register rn, int32_t offset = 0, AddrMode addrmode = Offset) + : rn_(rn), offset_(offset), rm_(no_reg), shift_(LSL), shift_imm_(0), addrmode_(addrmode) { + } + + MemOperand(Register rn, Register rm, AddrMode addrmode = Offset) + : rn_(rn), offset_(0), rm_(rm), shift_(LSL), shift_imm_(0), addrmode_(addrmode) { + } + + MemOperand(Register rn, Register rm, Shift shift, uint32_t shift_imm, AddrMode addrmode = Offset) + : rn_(rn), offset_(0), rm_(rm), shift_(shift), shift_imm_(shift_imm), addrmode_(addrmode) { + } + + const Register &rn() const { + return rn_; + } + const Register &rm() const { + return rm_; + } + int32_t offset() const { + return offset_; + } + + bool IsImmediateOffset() const { + return (addrmode_ == Offset); + } + bool IsRegisterOffset() const { + return (addrmode_ == Offset); + } + bool IsPreIndex() const { + return addrmode_ == PreIndex; + } + bool IsPostIndex() const { + return addrmode_ == PostIndex; + } + +private: + Register rn_; // base + Register rm_; // register offset + + int32_t offset_; // valid if rm_ == no_reg + + Shift shift_; + uint32_t shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg + + AddrMode addrmode_; // bits P, U, and W +}; + +// --- + +class OpEncode { +public: + static uint32_t MemOperand(const MemOperand operand) { + uint32_t encoding = 0; + if (operand.rm_.IsValid()) { + UNREACHABLE(); + } + + // sign + uint32_t U = 0; + if (operand.offset_ >= 0) { + U = (1 << 23); + } + encoding |= U; + + // offset + encoding |= bits(abs(operand.offset_), 0, 11); + + // addr mode + uint32_t P, W; + if (operand.addrmode_ == Offset) { + P = 1; + W = 0; + } else if (operand.addrmode_ == PostIndex) { + P = 0; + W = 0; + } else if (operand.addrmode_ == PreIndex) { + P = 1; + W = 1; + } + encoding |= ((P << 24) | (W << 21)); + + // rn + encoding |= Rn(operand.rn_); + + return encoding; + } + + static uint32_t Operand(const Operand operand) { + uint32_t encoding = 0; + if (operand.rm_.IsValid()) { + encoding = static_cast(operand.rm_.code()); + } else { + encoding = operand.GetImmediate(); + } + + return encoding; + } +}; + +// --- + +enum ExecuteState { ARMExecuteState, ThumbExecuteState }; + +class Assembler : public AssemblerBase { +private: + ExecuteState execute_state_; + +public: + Assembler(void *address) : AssemblerBase(address) { + execute_state_ = ARMExecuteState; + buffer_ = new CodeBuffer(); + } + + // shared_ptr is better choice + // but we can't use it at kernelspace + Assembler(void *address, CodeBuffer *buffer) : AssemblerBase(address) { + execute_state_ = ARMExecuteState; + buffer_ = buffer; + } + + void ClearCodeBuffer() { + buffer_ = NULL; + } + +public: + void SetExecuteState(ExecuteState state) { + execute_state_ = state; + } + ExecuteState GetExecuteState() { + return execute_state_; + } + + void SetRealizedAddress(void *address) { + DCHECK_EQ(0, reinterpret_cast(address) % 4); + AssemblerBase::SetRealizedAddress(address); + } + + void EmitARMInst(arm_inst_t instr); + + void EmitAddress(uint32_t value); + +public: + void sub(Register rd, Register rn, const Operand &operand) { + uint32_t encoding = B25 | B22; + add_sub(encoding, AL, rd, rn, operand); + } + + void add(Register rd, Register rn, const Operand &operand) { + uint32_t encoding = B25 | B23; + add_sub(encoding, AL, rd, rn, operand); + } + + void add_sub(uint32_t encoding, Condition cond, Register rd, Register rn, const Operand &operand) { + encoding |= (cond << kConditionShift); + + uint32_t imm = operand.GetImmediate(); + encoding |= imm; + + encoding |= Rd(rd); + + encoding |= Rn(rn); + + buffer_->EmitARMInst(encoding); + } + + void ldr(Register rt, const MemOperand &operand) { + uint32_t encoding = B20 | B26; + load_store(encoding, AL, rt, operand); + } + + void str(Register rt, const MemOperand &operand) { + uint32_t encoding = B26; + load_store(encoding, AL, rt, operand); + } + + void load_store(uint32_t encoding, Condition cond, Register rt, const MemOperand &operand) { + encoding |= (cond << kConditionShift); + encoding |= Rt(rt) | OpEncode::MemOperand(operand); + buffer_->EmitARMInst(encoding); + } + + void mov(Register rd, const Operand &operand) { + mov(AL, rd, operand); + } + + void mov(Condition cond, Register rd, const Operand &operand) { + uint32_t encoding = 0x01a00000; + encoding |= (cond << kConditionShift); + encoding |= Rd(rd) | OpEncode::Operand(operand); + buffer_->EmitARMInst(encoding); + } + + // Branch instructions. + void b(int branch_offset) { + b(AL, branch_offset); + } + void b(Condition cond, int branch_offset) { + uint32_t encoding = 0xa000000; + encoding |= (cond << kConditionShift); + uint32_t imm24 = bits(branch_offset >> 2, 0, 23); + encoding |= imm24; + buffer_->EmitARMInst(encoding); + } + + void bl(int branch_offset) { + bl(AL, branch_offset); + } + void bl(Condition cond, int branch_offset) { + uint32_t encoding = 0xb000000; + encoding |= (cond << kConditionShift); + uint32_t imm24 = bits(branch_offset >> 2, 0, 23); + encoding |= imm24; + buffer_->EmitARMInst(encoding); + } + + void blx(int branch_offset) { + UNIMPLEMENTED(); + } + void blx(Register target, Condition cond = AL) { + UNIMPLEMENTED(); + } + void bx(Register target, Condition cond = AL) { + UNIMPLEMENTED(); + } + +}; // namespace arm + +// --- + +class TurboAssembler : public Assembler { +public: + TurboAssembler(void *address) : Assembler(address) { + } + + ~TurboAssembler() { + } + + TurboAssembler(void *address, CodeBuffer *buffer) : Assembler(address, buffer) { + } + + void Ldr(Register rt, AssemblerPseudoLabel *label) { + if (label->relocated_pos()) { + int offset = label->relocated_pos() - buffer_->GetBufferSize(); + ldr(rt, MemOperand(pc, offset)); + } else { + // record this ldr, and fix later. + label->link_to(kLdrLiteral, 0, buffer_->GetBufferSize()); + ldr(rt, MemOperand(pc, 0)); + } + } + + void CallFunction(ExternalReference function) { + // trick: use bl to replace lr register + bl(0); + b(4); + ldr(pc, MemOperand(pc, -4)); + buffer_->Emit32((uint32_t)(uintptr_t)function.address()); + } + + void Move32Immeidate(Register rd, const Operand &x, Condition cond = AL) { + } + + void RelocLabelFixup(tinystl::unordered_map *relocated_offset_map) { + for (auto *data_label : data_labels_) { + auto val = data_label->data(); + auto iter = relocated_offset_map->find(val); + if (iter != relocated_offset_map->end()) { + data_label->fixup_data(iter->second); + } + } + } +}; + +} // namespace arm +} // namespace zz + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm64.cc b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm64.cc new file mode 100644 index 0000000..1cb7836 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm64.cc @@ -0,0 +1,25 @@ +#include "platform_macro.h" +#if TARGET_ARCH_ARM64 + +#include "core/assembler/assembler-arm64.h" + +void AssemblerPseudoLabel::link_confused_instructions(CodeBufferBase *buffer) { + CodeBuffer *_buffer = (CodeBuffer *)buffer; + + for (auto &ref_label_inst : ref_label_insts_) { + int64_t fixup_offset = relocated_pos() - ref_label_inst.offset_; + + arm64_inst_t inst = _buffer->LoadInst(ref_label_inst.offset_); + arm64_inst_t new_inst = 0; + + if (ref_label_inst.type_ == kLabelImm19) { + new_inst = encode_imm19_offset(inst, fixup_offset); + } + + _buffer->RewriteInst(ref_label_inst.offset_, new_inst); + } +} + +using namespace zz::arm64; + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm64.h b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm64.h new file mode 100644 index 0000000..53b8c2a --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-arm64.h @@ -0,0 +1,563 @@ +#ifndef CORE_ASSEMBLER_ARM64_H +#define CORE_ASSEMBLER_ARM64_H + +#include "dobby_internal.h" + +#include "core/arch/arm64/constants-arm64.h" +#include "core/arch/arm64/registers-arm64.h" +#include "core/assembler/assembler.h" + +#include "MemoryAllocator/CodeBuffer/code_buffer_arm64.h" + +#include "InstructionRelocation/arm64/inst_decode_encode_kit.h" + +static inline uint16_t Low16Bits(uint32_t value) { + return static_cast(value & 0xffff); +} + +static inline uint16_t High16Bits(uint32_t value) { + return static_cast(value >> 16); +} + +static inline uint32_t Low32Bits(uint64_t value) { + return static_cast(value); +} + +static inline uint32_t High32Bits(uint64_t value) { + return static_cast(value >> 32); +} + +enum ref_label_type_t { kLabelImm19 }; + +namespace zz { +namespace arm64 { + +constexpr Register TMP_REG_0 = X(ARM64_TMP_REG_NDX_0); + +#define Rd(rd) (rd.code() << kRdShift) +#define Rt(rt) (rt.code() << kRtShift) +#define Rt2(rt) (rt.code() << kRt2Shift) +#define Rn(rn) (rn.code() << kRnShift) +#define Rm(rm) (rm.code() << kRmShift) + +// --- + +class Operand { +public: + inline explicit Operand(int64_t imm) + : immediate_(imm), reg_(InvalidRegister), shift_(NO_SHIFT), extend_(NO_EXTEND), shift_extent_imm_(0) { + } + inline Operand(Register reg, Shift shift = LSL, int32_t shift_imm = 0) + : immediate_(0), reg_(reg), shift_(shift), extend_(NO_EXTEND), shift_extent_imm_(shift_imm) { + } + inline Operand(Register reg, Extend extend, int32_t shift_imm = 0) + : immediate_(0), reg_(reg), shift_(NO_SHIFT), extend_(extend), shift_extent_imm_(shift_imm) { + } + + bool IsImmediate() const { + return reg_.Is(InvalidRegister); + } + bool IsShiftedRegister() const { + return /* reg_.IsValid() && */ (shift_ != NO_SHIFT); + } + bool IsExtendedRegister() const { + return /* reg_.IsValid() && */ (extend_ != NO_EXTEND); + } + + Register reg() const { + DCHECK((IsShiftedRegister() || IsExtendedRegister())); + return reg_; + } + int64_t Immediate() const { + return immediate_; + } + Shift shift() const { + DCHECK(IsShiftedRegister()); + return shift_; + } + Extend extend() const { + DCHECK(IsExtendedRegister()); + return extend_; + } + int32_t shift_extend_imm() const { + return shift_extent_imm_; + } + +private: + int64_t immediate_; + + Register reg_; + + Shift shift_; + Extend extend_; + int32_t shift_extent_imm_; +}; + +// --- + +class MemOperand { +public: + inline explicit MemOperand(Register base, int64_t offset = 0, AddrMode addrmode = Offset) + : base_(base), regoffset_(InvalidRegister), offset_(offset), addrmode_(addrmode), shift_(NO_SHIFT), + extend_(NO_EXTEND), shift_extend_imm_(0) { + } + + inline explicit MemOperand(Register base, Register regoffset, Extend extend, unsigned extend_imm) + : base_(base), regoffset_(regoffset), offset_(0), addrmode_(Offset), shift_(NO_SHIFT), extend_(extend), + shift_extend_imm_(extend_imm) { + } + + inline explicit MemOperand(Register base, Register regoffset, Shift shift = LSL, unsigned shift_imm = 0) + : base_(base), regoffset_(regoffset), offset_(0), addrmode_(Offset), shift_(shift), extend_(NO_EXTEND), + shift_extend_imm_(shift_imm) { + } + + inline explicit MemOperand(Register base, const Operand &offset, AddrMode addrmode = Offset) + : base_(base), regoffset_(InvalidRegister), addrmode_(addrmode) { + if (offset.IsShiftedRegister()) { + regoffset_ = offset.reg(); + shift_ = offset.shift(); + shift_extend_imm_ = offset.shift_extend_imm(); + + extend_ = NO_EXTEND; + offset_ = 0; + } else if (offset.IsExtendedRegister()) { + regoffset_ = offset.reg(); + extend_ = offset.extend(); + shift_extend_imm_ = offset.shift_extend_imm(); + + shift_ = NO_SHIFT; + offset_ = 0; + } + } + + const Register &base() const { + return base_; + } + const Register ®offset() const { + return regoffset_; + } + int64_t offset() const { + return offset_; + } + AddrMode addrmode() const { + return addrmode_; + } + Shift shift() const { + return shift_; + } + Extend extend() const { + return extend_; + } + unsigned shift_extend_imm() const { + return shift_extend_imm_; + } + + bool IsImmediateOffset() const { + return (addrmode_ == Offset); + } + bool IsRegisterOffset() const { + return (addrmode_ == Offset); + } + bool IsPreIndex() const { + return addrmode_ == PreIndex; + } + bool IsPostIndex() const { + return addrmode_ == PostIndex; + } + +private: + Register base_; + Register regoffset_; + + int64_t offset_; + + Shift shift_; + Extend extend_; + uint32_t shift_extend_imm_; + + AddrMode addrmode_; +}; + +// --- + +class OpEncode { +public: + static int32_t sf(const Register ®, int32_t op) { + return (op | sf(reg)); + } + + // register operation size, 32 bits or 64 bits + static int32_t sf(const Register ®) { + if (reg.Is64Bits()) + return LeftShift(1, 1, 31); + return 0; + } + + static int32_t V(const Register ®, int32_t op) { + return (op | V(reg)); + } + + // register type, SIMD_FD register or general register + static int32_t V(const Register ®) { + if (reg.IsVRegister()) + return LeftShift(1, 1, 26); + return 0; + } + + // load or store + static int32_t L(bool load_or_store) { + if (load_or_store) { + return LeftShift(1, 1, 22); + } + return 0; + } + + // shift type + static int32_t shift(Shift shift) { + return LeftShift(shift, 2, 22); + } + + // LogicalImmeidate + static int32_t EncodeLogicalImmediate(const Register &rd, const Register &rn, const Operand &operand) { + int64_t imm = operand.Immediate(); + int32_t N, imms, immr; + immr = bits(imm, 0, 5); + imms = bits(imm, 6, 11); + N = bit(imm, 12); + + return (sf(rd) | LeftShift(immr, 6, 16) | LeftShift(imms, 6, 10) | Rd(rd) | Rn(rn)); + } + + // LogicalShift + static int32_t EncodeLogicalShift(const Register &rd, const Register &rn, const Operand &operand) { + return (sf(rd) | shift(operand.shift()) | Rm(operand.reg()) | LeftShift(operand.shift_extend_imm(), 6, 10) | + Rn(rn) | Rd(rd)); + } + + // LoadStore + static int32_t LoadStorePair(LoadStorePairOp op, CPURegister rt, CPURegister rt2, const MemOperand &addr) { + int32_t scale = 2; + int32_t opc = 0; + int imm7; + opc = bits(op, 30, 31); + if (rt.IsRegister()) { + scale += bit(opc, 1); + } else if (rt.IsVRegister()) { + scale += opc; + } + + imm7 = (int)(addr.offset() >> scale); + return LeftShift(imm7, 7, 15); + } + + // scale + static int32_t scale(int32_t op) { + int scale = 0; + if ((op & LoadStoreUnsignedOffsetFixed) == LoadStoreUnsignedOffsetFixed) { + scale = bits(op, 30, 31); + } + return scale; + } +}; + +// --- + +class Assembler : public AssemblerBase { +public: + Assembler(void *address) : AssemblerBase(address) { + buffer_ = new CodeBuffer(); + } + + ~Assembler() { + if (buffer_) + delete buffer_; + buffer_ = NULL; + } + +public: + void SetRealizedAddress(void *address) { + DCHECK_EQ(0, reinterpret_cast(address) % 4); + AssemblerBase::SetRealizedAddress(address); + } + + void Emit(uint32_t value) { + buffer_->Emit32(value); + } + + void EmitInt64(int64_t value) { + buffer_->Emit64(value); + } + + void bind(Label *label); + + void nop() { + Emit(0xD503201F); + } + + void brk(int code) { + Emit(BRK | LeftShift(code, 16, 5)); + } + + void ret() { + Emit(0xD65F03C0); + } + + void adrp(const Register &rd, int64_t imm) { + DCHECK(rd.Is64Bits()); + DCHECK((abs(imm) >> 12) < (1 << 21)); + + uint32_t immlo = LeftShift(bits(imm >> 12, 0, 1), 2, 29); + uint32_t immhi = LeftShift(bits(imm >> 12, 2, 20), 19, 5); + Emit(ADRP | Rd(rd) | immlo | immhi); + } + + void add(const Register &rd, const Register &rn, int64_t imm) { + if (rd.Is64Bits() && rn.Is64Bits()) + AddSubImmediate(rd, rn, Operand(imm), OPT_X(ADD, imm)); + else + AddSubImmediate(rd, rn, Operand(imm), OPT_W(ADD, imm)); + } + + void adds(const Register &rd, const Register &rn, int64_t imm) { + UNREACHABLE(); + } + void sub(const Register &rd, const Register &rn, int64_t imm) { + if (rd.Is64Bits() && rn.Is64Bits()) + AddSubImmediate(rd, rn, Operand(imm), OPT_X(SUB, imm)); + else + AddSubImmediate(rd, rn, Operand(imm), OPT_W(SUB, imm)); + } + void subs(const Register &rd, const Register &rn, int64_t imm) { + UNREACHABLE(); + } + + void b(int64_t imm) { + int32_t imm26 = bits(imm >> 2, 0, 25); + + Emit(B | imm26); + } + + void b(Label *label) { + int offset = LinkAndGetByteOffsetTo(label); + b(offset); + } + + void br(Register rn) { + Emit(BR | Rn(rn)); + } + + void blr(Register rn) { + Emit(BLR | Rn(rn)); + } + + void ldr(Register rt, int64_t imm) { + LoadRegLiteralOp op; + switch (rt.type()) { + case CPURegister::kRegister_32: + op = OPT_W(LDR, literal); + break; + case CPURegister::kRegister_X: + op = OPT_X(LDR, literal); + break; + case CPURegister::kSIMD_FP_Register_S: + op = OPT_S(LDR, literal); + break; + case CPURegister::kSIMD_FP_Register_D: + op = OPT_D(LDR, literal); + break; + case CPURegister::kSIMD_FP_Register_Q: + op = OPT_Q(LDR, literal); + break; + default: + UNREACHABLE(); + break; + } + EmitLoadRegLiteral(op, rt, imm); + } + + void ldr(const CPURegister &rt, const MemOperand &src) { + LoadStore(OP_X(LDR), rt, src); + } + + void str(const CPURegister &rt, const MemOperand &src) { + LoadStore(OP_X(STR), rt, src); + } + + void ldp(const Register &rt, const Register &rt2, const MemOperand &src) { + if (rt.type() == Register::kSIMD_FP_Register_128) { + LoadStorePair(OP_Q(LDP), rt, rt2, src); + } else if (rt.type() == Register::kRegister_X) { + LoadStorePair(OP_X(LDP), rt, rt2, src); + } else { + UNREACHABLE(); + } + } + + void stp(const Register &rt, const Register &rt2, const MemOperand &dst) { + if (rt.type() == Register::kSIMD_FP_Register_128) { + LoadStorePair(OP_Q(STP), rt, rt2, dst); + } else if (rt.type() == Register::kRegister_X) { + LoadStorePair(OP_X(STP), rt, rt2, dst); + } else { + UNREACHABLE(); + } + } + + void mov(const Register &rd, const Register &rn) { + if ((rd.Is(SP)) || (rn.Is(SP))) { + add(rd, rn, 0); + } else { + if (rd.Is64Bits()) + orr(rd, xzr, Operand(rn)); + else + orr(rd, wzr, Operand(rn)); + } + } + void movk(const Register &rd, uint64_t imm, int shift = -1) { + // Move and keep. + MoveWide(rd, imm, shift, MOVK); + } + void movn(const Register &rd, uint64_t imm, int shift = -1) { + // Move with non-zero. + MoveWide(rd, imm, shift, MOVN); + } + void movz(const Register &rd, uint64_t imm, int shift = -1) { + // Move with zero. + MoveWide(rd, imm, shift, MOVZ); + } + + void orr(const Register &rd, const Register &rn, const Operand &operand) { + Logical(rd, rn, operand, ORR); + } + +private: + // label helpers. + static constexpr int kStartOfLabelLinkChain = 0; + int LinkAndGetByteOffsetTo(Label *label); + + // load helpers. + void EmitLoadRegLiteral(LoadRegLiteralOp op, CPURegister rt, int64_t imm) { + const int32_t encoding = op | LeftShift(imm, 26, 5) | Rt(rt); + Emit(encoding); + } + + void LoadStore(LoadStoreOp op, CPURegister rt, const MemOperand &addr) { + int64_t imm12 = addr.offset(); + if (addr.IsImmediateOffset()) { + // TODO: check Scaled ??? + imm12 = addr.offset() >> OpEncode::scale(LoadStoreUnsignedOffsetFixed | op); + Emit(LoadStoreUnsignedOffsetFixed | op | LeftShift(imm12, 12, 10) | Rn(addr.base()) | Rt(rt)); + } else if (addr.IsRegisterOffset()) { + UNREACHABLE(); + } else { + // pre-index & post-index + UNREACHABLE(); + } + } + + void LoadStorePair(LoadStorePairOp op, CPURegister rt, CPURegister rt2, const MemOperand &addr) { + int32_t combine_fields_op = OpEncode::LoadStorePair(op, rt, rt2, addr) | Rt2(rt2) | Rn(addr.base()) | Rt(rt); + int32_t addrmodeop; + + if (addr.IsImmediateOffset()) { + addrmodeop = LoadStorePairOffsetFixed; + } else { + if (addr.IsPreIndex()) { + addrmodeop = LoadStorePairPreIndexFixed; + } else { + addrmodeop = LoadStorePairPostIndexFixed; + } + } + Emit(op | addrmodeop | combine_fields_op); + } + + void MoveWide(Register rd, uint64_t imm, int shift, MoveWideImmediateOp op) { + if (shift > 0) + shift /= 16; + else + shift = 0; + + int32_t imm16 = LeftShift(imm, 16, 5); + Emit(MoveWideImmediateFixed | op | OpEncode::sf(rd) | LeftShift(shift, 2, 21) | imm16 | Rd(rd)); + } + + void AddSubImmediate(const Register &rd, const Register &rn, const Operand &operand, AddSubImmediateOp op) { + if (operand.IsImmediate()) { + int64_t immediate = operand.Immediate(); + int32_t imm12 = LeftShift(immediate, 12, 10); + Emit(op | Rd(rd) | Rn(rn) | imm12); + } else { + UNREACHABLE(); + } + } + + void Logical(const Register &rd, const Register &rn, const Operand &operand, LogicalOp op) { + if (operand.IsImmediate()) { + LogicalImmediate(rd, rn, operand, op); + } else { + LogicalShift(rd, rn, operand, op); + } + } + void LogicalImmediate(const Register &rd, const Register &rn, const Operand &operand, LogicalOp op) { + int32_t combine_fields_op = OpEncode::EncodeLogicalImmediate(rd, rn, operand); + Emit(op | combine_fields_op); + } + void LogicalShift(const Register &rd, const Register &rn, const Operand &operand, LogicalOp op) { + int32_t combine_fields_op = OpEncode::EncodeLogicalShift(rd, rn, operand); + Emit(op | LogicalShiftedFixed | combine_fields_op); + } +}; + +// --- + +class TurboAssembler : public Assembler { +public: + TurboAssembler(void *address) : Assembler(address) { + } + + ~TurboAssembler() { + } + + void CallFunction(ExternalReference function) { + Mov(TMP_REG_0, (uint64_t)function.address()); + blr(TMP_REG_0); + } + + void Ldr(Register rt, AssemblerPseudoLabel *label) { + if (label->relocated_pos()) { + int offset = label->relocated_pos() - buffer_->GetBufferSize(); + ldr(rt, offset); + } else { + label->link_to(kLabelImm19, 0, buffer_->GetBufferSize()); + ldr(rt, 0); + } + } + + void Mov(Register rd, uint64_t imm) { + const uint32_t w0 = Low32Bits(imm); + const uint32_t w1 = High32Bits(imm); + const uint16_t h0 = Low16Bits(w0); + const uint16_t h1 = High16Bits(w0); + const uint16_t h2 = Low16Bits(w1); + const uint16_t h3 = High16Bits(w1); + movz(rd, h0, 0); + movk(rd, h1, 16); + movk(rd, h2, 32); + movk(rd, h3, 48); + } + + void AdrpAdd(Register rd, uint64_t from, uint64_t to) { + uint64_t from_PAGE = ALIGN(from, 0x1000); + uint64_t to_PAGE = ALIGN(to, 0x1000); + uint64_t to_PAGEOFF = (uint64_t)to % 0x1000; + + adrp(rd, to_PAGE - from_PAGE); + add(rd, rd, to_PAGEOFF); + } +}; + +} // namespace arm64 +} // namespace zz + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-ia32.cc b/app/src/main/cpp/Dobby/source/core/assembler/assembler-ia32.cc new file mode 100644 index 0000000..dd30472 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-ia32.cc @@ -0,0 +1,34 @@ +#include "platform_macro.h" +#if TARGET_ARCH_IA32 + +#include "core/assembler/assembler-ia32.h" + +using namespace zz::x86; + +void Assembler::jmp(Immediate imm) { + buffer_->Emit8(0xE9); + buffer_->Emit32((int)imm.value()); +} + +addr32_t TurboAssembler::CurrentIP() { + return pc_offset() + (addr_t)realized_addr_; +} + +void AssemblerPseudoLabel::link_confused_instructions(CodeBufferBase *buffer) { + auto _buffer = (CodeBuffer *)buffer; + + for (auto &ref_label_inst : ref_label_insts_) { + int64_t new_offset = relocated_pos() - ref_label_inst.offset_; + + if (ref_label_inst.type_ == kDisp32_off_7) { + // why 7 ? + // use `call` and `pop` get the runtime ip register + // but the ip register not the real call next insn + // it need add two insn length == 7 + int disp32_fix_pos = ref_label_inst.offset_ - sizeof(int32_t); + _buffer->FixBindLabel(disp32_fix_pos, new_offset + 7); + } + } +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-ia32.h b/app/src/main/cpp/Dobby/source/core/assembler/assembler-ia32.h new file mode 100644 index 0000000..5530a55 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-ia32.h @@ -0,0 +1,470 @@ +#ifndef CORE_ASSEMBLER_X86_H +#define CORE_ASSEMBLER_X86_H + +#include "common_header.h" + +#include "core/arch/x86/registers-x86.h" +#include "core/assembler/assembler.h" + +#include "MemoryAllocator/CodeBuffer/code_buffer_x86.h" + +#define IsInt8(imm) (-128 <= imm && imm <= 127) + +enum ref_label_type_t { kDisp32_off_7 }; + + +namespace zz { +namespace x86 { + +constexpr Register VOLATILE_REGISTER = eax; + +#define ModRM_Mod(byte) ((byte & 0b11000000) >> 6) +#define ModRM_RegOpcode(byte) ((byte & 0b00111000) >> 3) +#define ModRM_RM(byte) (byte & 0b00000111) + +typedef union _ModRM { + byte_t ModRM; + struct { + byte_t RM : 3; + byte_t RegOpcode : 3; + byte_t Mod : 2; + }; +} ModRM; + +// --- + + +class Immediate { +public: + explicit Immediate(int32_t imm) : value_(imm), value_size_(32) { + if ((int32_t)(int8_t)imm == imm) { + value_size_ = 8; + } else if ((int32_t)(int16_t)imm == imm) { + value_size_ = 16; + } else { + value_size_ = 32; + } + } + + explicit Immediate(int32_t imm, int size) : value_(imm), value_size_(size) { + } + + int32_t value() const { + return value_; + } + + int size() const { + return value_size_; + } + +private: + const int32_t value_; + + int value_size_; +}; + +// --- + +class Operand { +public: + // [base] + Operand(Register base); + + // [base + disp/r] + Operand(Register base, int32_t disp); + + // [base + index*scale + disp/r] + Operand(Register base, Register index, ScaleFactor scale, int32_t disp); + + // [index*scale + disp/r] + Operand(Register index, ScaleFactor scale, int32_t disp); + +public: // Getter and Setter + uint8_t modrm() { + return (encoding_at(0)); + } + + uint8_t mod() const { + return (encoding_at(0) >> 6) & 3; + } + + Register rm() const { + return Register::from_code(encoding_at(0) & 7); + } + + ScaleFactor scale() const { + return static_cast((encoding_at(1) >> 6) & 3); + } + + Register index() const { + return Register::from_code((encoding_at(1) >> 3) & 7); + } + + Register base() const { + return Register::from_code(encoding_at(1) & 7); + } + + int8_t disp8() const { + ASSERT(length_ >= 2); + return static_cast(encoding_[length_ - 1]); + } + + int32_t disp32() const { + ASSERT(length_ >= 5); + return static_cast(encoding_[length_ - 4]); + } + +protected: + Operand() : length_(0) { + } + + void SetModRM(int mod, Register rm) { + ASSERT((mod & ~3) == 0); + encoding_[0] = (mod << 6) | rm.code(); + length_ = 1; + } + + void SetSIB(ScaleFactor scale, Register index, Register base) { + ASSERT(length_ == 1); + ASSERT((scale & ~3) == 0); + encoding_[1] = (scale << 6) | (index.code() << 3) | base.code(); + length_ = 2; + } + + void SetDisp8(int8_t disp) { + ASSERT(length_ == 1 || length_ == 2); + encoding_[length_++] = static_cast(disp); + } + + void SetDisp32(int32_t disp) { + ASSERT(length_ == 1 || length_ == 2); + *(int32_t *)&encoding_[length_] = disp; + length_ += sizeof(disp); + } + +private: + // explicit Operand(Register reg) : rex_(REX_NONE) { SetModRM(3, reg); } + + // Get the operand encoding byte at the given index. + uint8_t encoding_at(intptr_t index) const { + ASSERT(index >= 0 && index < length_); + return encoding_[index]; + } + +public: + uint8_t length_; + uint8_t encoding_[6]; +}; + +// --- + + +class Address : public Operand { +public: + Address(Register base, int32_t disp) { + int base_ = base.code(); + int ebp_ = ebp.code(); + int esp_ = esp.code(); + if ((disp == 0) && (base_ != ebp_)) { + SetModRM(0, base); + if (base_ == esp_) + SetSIB(TIMES_1, esp, base); + } else if (disp >= -128 && disp <= 127) { + SetModRM(1, base); + if (base_ == esp_) + SetSIB(TIMES_1, esp, base); + SetDisp8(disp); + } else { + SetModRM(2, base); + if (base_ == esp_) + SetSIB(TIMES_1, esp, base); + SetDisp32(disp); + } + } + + // This addressing mode does not exist. + Address(Register base, Register r); + + Address(Register index, ScaleFactor scale, int32_t disp) { + ASSERT(index.code() != rsp.code()); // Illegal addressing mode. + SetModRM(0, esp); + SetSIB(scale, index, ebp); + SetDisp32(disp); + } + + // This addressing mode does not exist. + Address(Register index, ScaleFactor scale, Register r); + + Address(Register base, Register index, ScaleFactor scale, int32_t disp) { + ASSERT(index.code() != rsp.code()); // Illegal addressing mode. + int rbp_ = ebp.code(); + if ((disp == 0) && ((base.code() & 7) != rbp_)) { + SetModRM(0, esp); + SetSIB(scale, index, base); + } else if (disp >= -128 && disp <= 127) { + SetModRM(1, esp); + SetSIB(scale, index, base); + SetDisp8(disp); + } else { + SetModRM(2, esp); + SetSIB(scale, index, base); + SetDisp32(disp); + } + } + + // This addressing mode does not exist. + Address(Register base, Register index, ScaleFactor scale, Register r); + +private: + Address(Register base, int32_t disp, bool fixed) { + ASSERT(fixed); + + SetModRM(2, base); + if (base.code() == esp.code()) { + SetSIB(TIMES_1, esp, base); + } + SetDisp32(disp); + } +}; + +// --- + + +class Assembler : public AssemblerBase { +public: + Assembler(void *address) : AssemblerBase(address) { + buffer_ = new CodeBuffer(); + } + ~Assembler() { + if (buffer_) + delete buffer_; + buffer_ = NULL; + } + +public: + void Emit1(byte_t val) { + buffer_->Emit8(val); + } + + void Emit(int32_t value) { + buffer_->Emit32(value); + } + + // --- + + + void EmitImmediate(Immediate imm, int imm_size) { + if (imm_size == 8) { + buffer_->Emit8((uint8_t)imm.value()); + } else if (imm_size == 32) { + buffer_->Emit32((uint32_t)imm.value()); + } else { + UNREACHABLE(); + } + } + + // --- + + + // ATTENTION: + // ModR/M == 8 registers and 24 addressing mode + + void Emit_OpEn_Register_MemOperand(Register dst, Address &operand) { + EmitModRM_Update_Register(operand.modrm(), dst); + buffer_->EmitBuffer(&operand.encoding_[1], operand.length_ - 1); + } + + void Emit_OpEn_Register_RegOperand(Register dst, Register src) { + EmitModRM_Register_Register(dst, src); + } + + void Emit_OpEn_MemOperand_Immediate(uint8_t extra_opcode, Address &operand, Immediate imm) { + EmitModRM_Update_ExtraOpcode(operand.modrm(), extra_opcode); + buffer_->EmitBuffer(&operand.encoding_[1], operand.length_ - 1); + EmitImmediate(imm, imm.size()); + } + + void Emit_OpEn_RegOperand_Immediate(uint8_t extra_opcode, Register reg, Immediate imm) { + EmitModRM_ExtraOpcode_Register(extra_opcode, reg); + EmitImmediate(imm, imm.size()); + } + + void Emit_OpEn_MemOperand(uint8_t extra_opcode, Address &operand) { + EmitModRM_Update_ExtraOpcode(operand.modrm(), extra_opcode); + buffer_->EmitBuffer(&operand.encoding_[1], operand.length_ - 1); + } + + void Emit_OpEn_RegOperand(uint8_t extra_opcode, Register reg) { + EmitModRM_ExtraOpcode_Register(extra_opcode, reg); + } + + // Encoding: OI + void Emit_OpEn_OpcodeRegister_Immediate(uint8_t opcode, Register dst, Immediate imm) { + EmitOpcode_Register(opcode, dst); + EmitImmediate(imm, imm.size()); + } + + // --- + + + inline void EmitModRM(uint8_t Mod, uint8_t RegOpcode, uint8_t RM) { + uint8_t ModRM = 0; + ModRM |= Mod << 6; + ModRM |= RegOpcode << 3; + ModRM |= RM; + Emit1(ModRM); + } + + void EmitModRM_ExtraOpcode_Register(uint8_t extra_opcode, Register reg) { + EmitModRM(0b11, extra_opcode, reg.code()); + } + + void EmitModRM_Register_Register(Register reg1, Register reg2) { + EmitModRM(0b11, reg1.code(), reg2.code()); + } + + // update operand's ModRM + void EmitModRM_Update_Register(uint8_t modRM, Register reg) { + EmitModRM(ModRM_Mod(modRM), reg.code(), ModRM_RM(modRM)); + } + + // update operand's ModRM + void EmitModRM_Update_ExtraOpcode(uint8_t modRM, uint8_t extra_opcode) { + EmitModRM(ModRM_Mod(modRM), extra_opcode, ModRM_RM(modRM)); + } + + // --- + + void EmitOpcode(uint8_t opcode) { + Emit1(opcode); + } + + void EmitOpcode_Register(uint8_t opcode, Register reg) { + EmitOpcode(opcode | reg.code()); + } + + // --- + + + void pushfq() { + Emit1(0x9C); + } + + void jmp(Immediate imm); + + void sub(Register dst, Immediate imm) { + DCHECK_EQ(dst.size(), 32); + + EmitOpcode(0x81); + + Emit_OpEn_RegOperand_Immediate(0x5, dst, imm); + } + + void add(Register dst, Immediate imm) { + DCHECK_EQ(dst.size(), 32); + + EmitOpcode(0x81); + + Emit_OpEn_RegOperand_Immediate(0x0, dst, imm); + } + + // MOV RAX, 0x320 + // 48 c7 c0 20 03 00 00 (MI encoding) + // 48 b8 20 03 00 00 00 00 00 00 (OI encoding) + void mov(Register dst, const Immediate imm) { + Emit_OpEn_OpcodeRegister_Immediate(0xb8, dst, imm); + } + + void mov(Address dst, const Immediate imm) { + EmitOpcode(0xc7); + + Emit_OpEn_MemOperand_Immediate(0x0, dst, imm); + } + + void mov(Register dst, Address src) { + EmitOpcode(0x8B); + + Emit_OpEn_Register_MemOperand(dst, src); + } + + void mov(Address dst, Register src) { + EmitOpcode(0x89); + + Emit_OpEn_Register_MemOperand(src, dst); + } + + void mov(Register dst, Register src) { + Emit1(0x8B); + + Emit_OpEn_Register_RegOperand(dst, src); + } + + void call(Address operand) { + EmitOpcode(0xFF); + + Emit_OpEn_MemOperand(0x2, operand); + } + + void call(Immediate imm) { + EmitOpcode(0xe8); + + EmitImmediate(imm, imm.size()); + } + + void call(Register reg) { + EmitOpcode(0xFF); + + Emit_OpEn_RegOperand(0x2, reg); + } + + void pop(Register reg) { + EmitOpcode_Register(0x58, reg); + } + + void push(Register reg) { + EmitOpcode_Register(0x50, reg); + } + + void ret() { + EmitOpcode(0xc3); + } + void nop() { + EmitOpcode(0x90); + } +}; + +// --- + + +class TurboAssembler : public Assembler { +public: + TurboAssembler(void *address) : Assembler(address) { + } + + ~TurboAssembler() { + } + + addr32_t CurrentIP(); + + void CallFunction(ExternalReference function) { + nop(); + MovRipToRegister(VOLATILE_REGISTER); + call(Address(VOLATILE_REGISTER, INT32_MAX)); + { + RelocLabel *addr_label = new RelocLabel(function.address()); + addr_label->link_to(kDisp32_off_7, 0, ip_offset()); + this->AppendRelocLabel(addr_label); + } + nop(); + } + + void MovRipToRegister(Register dst) { + call(Immediate(0, 32)); + pop(dst); + } +}; + +} // namespace x86 +} // namespace zz + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-x64.cc b/app/src/main/cpp/Dobby/source/core/assembler/assembler-x64.cc new file mode 100644 index 0000000..bb7910b --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-x64.cc @@ -0,0 +1,34 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_X64) + +#include "core/assembler/assembler-x64.h" + +using namespace zz::x64; + +void AssemblerPseudoLabel::link_confused_instructions(CodeBufferBase *buffer) { + CodeBuffer *_buffer = (CodeBuffer *)buffer; + + for (auto &ref_label_inst : ref_label_insts_) { + int64_t new_offset = relocated_pos() - ref_label_inst.offset_; + + if (ref_label_inst.type_ == kDisp32_off_9) { + // why 9 ? + // use `call` and `pop` get the runtime ip register + // but the ip register not the real call next insn + // it need add two insn length == 9 + int disp32_fix_pos = ref_label_inst.offset_ - sizeof(int32_t); + _buffer->FixBindLabel(disp32_fix_pos, new_offset + 9); + } + } +} + +void Assembler::jmp(Immediate imm) { + buffer_->Emit8(0xE9); + buffer_->Emit32((int)imm.value()); +} + +addr64_t TurboAssembler::CurrentIP() { + return pc_offset() + (addr_t)realized_addr_; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-x64.h b/app/src/main/cpp/Dobby/source/core/assembler/assembler-x64.h new file mode 100644 index 0000000..38b3513 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-x64.h @@ -0,0 +1,596 @@ +#pragma once + +#include "common_header.h" + +#include "core/arch/x64/registers-x64.h" +#include "core/assembler/assembler.h" + +#include "MemoryAllocator/CodeBuffer/code_buffer_x64.h" + +#define IsInt8(imm) (-128 <= imm && imm <= 127) + +enum ref_label_type_t { kDisp32_off_9 }; + +namespace zz { +namespace x64 { + +constexpr Register VOLATILE_REGISTER = r11; + +#define ModRM_Mod(byte) ((byte & 0b11000000) >> 6) +#define ModRM_RegOpcode(byte) ((byte & 0b00111000) >> 3) +#define ModRM_RM(byte) (byte & 0b00000111) + +typedef union _ModRM { + byte_t ModRM; + struct { + byte_t RM : 3; + byte_t RegOpcode : 3; + byte_t Mod : 2; + }; +} ModRM; + +// --- + +class Immediate { +public: + explicit Immediate(int64_t imm) : value_(imm), value_size_(64) { + if ((int64_t)(int8_t)imm == imm) { + value_size_ = 8; + } else if ((int64_t)(int16_t)imm == imm) { + value_size_ = 8; + } else if ((int64_t)(int32_t)imm == imm) { + value_size_ = 32; + } else { + value_size_ = 64; + } + } + + explicit Immediate(int64_t imm, int size) : value_(imm), value_size_(size) { + } + + int64_t value() const { + return value_; + } + + int size() const { + return value_size_; + } + +private: + const int64_t value_; + + int value_size_; +}; + +// --- + +class Operand { +public: + // [base] + Operand(Register base); + + // [base + disp/r] + Operand(Register base, int32_t disp); + + // [base + index*scale + disp/r] + Operand(Register base, Register index, ScaleFactor scale, int32_t disp); + + // [index*scale + disp/r] + Operand(Register index, ScaleFactor scale, int32_t disp); + +public: // Getter and Setter + uint8_t rex() const { + return rex_; + } + + inline uint8_t rex_b() const { + return (rex_ & REX_B); + } + + inline uint8_t rex_x() const { + return (rex_ & REX_X); + } + + inline uint8_t rex_r() const { + return (rex_ & REX_R); + } + + inline uint8_t rex_w() const { + return (rex_ & REX_W); + } + + uint8_t modrm() { + return (encoding_at(0)); + } + + uint8_t mod() const { + return (encoding_at(0) >> 6) & 3; + } + + Register rm() const { + int rm_rex = rex_b() << 3; + return Register::from_code(rm_rex + (encoding_at(0) & 7)); + } + + ScaleFactor scale() const { + return static_cast((encoding_at(1) >> 6) & 3); + } + + Register index() const { + int index_rex = rex_x() << 2; + return Register::from_code(index_rex + ((encoding_at(1) >> 3) & 7)); + } + + Register base() const { + int base_rex = rex_b() << 3; + return Register::from_code(base_rex + (encoding_at(1) & 7)); + } + + int8_t disp8() const { + ASSERT(length_ >= 2); + return static_cast(encoding_[length_ - 1]); + } + + int32_t disp32() const { + ASSERT(length_ >= 5); + return static_cast(encoding_[length_ - 4]); + } + +protected: + Operand() : length_(0), rex_(REX_NONE) { + } // Needed by subclass Address. + + void SetModRM(int mod, Register rm) { + ASSERT((mod & ~3) == 0); + + if ((rm.code() > 7) && !((rm.Is(r12)) && (mod != 3))) { + rex_ |= REX_B; + } + encoding_[0] = (mod << 6) | (rm.code() & 7); + length_ = 1; + } + + void SetSIB(ScaleFactor scale, Register index, Register base) { + ASSERT(length_ == 1); + ASSERT((scale & ~3) == 0); + + if (base.code() > 7) { + ASSERT((rex_ & REX_B) == 0); // Must not have REX.B already set. + rex_ |= REX_B; + } + if (index.code() > 7) + rex_ |= REX_X; + + encoding_[1] = (scale << 6) | ((index.code() & 7) << 3) | (base.code() & 7); + length_ = 2; + } + + void SetDisp8(int8_t disp) { + ASSERT(length_ == 1 || length_ == 2); + + encoding_[length_++] = static_cast(disp); + } + + void SetDisp32(int32_t disp) { + ASSERT(length_ == 1 || length_ == 2); + + *(int32_t *)&encoding_[length_] = disp; + length_ += sizeof(disp); + } + +private: + // explicit Operand(Register reg) : rex_(REX_NONE) { SetModRM(3, reg); } + + // Get the operand encoding byte at the given index. + uint8_t encoding_at(intptr_t index) const { + ASSERT(index >= 0 && index < length_); + return encoding_[index]; + } + +public: + uint8_t length_; + uint8_t rex_; + uint8_t encoding_[6]; +}; + +// --- + +class Address : public Operand { +public: + Address(Register base, int32_t disp) { + int base_ = base.code(); + int rbp_ = rbp.code(); + int rsp_ = rsp.code(); + if ((disp == 0) && ((base_ & 7) != rbp_)) { + SetModRM(0, base); + if ((base_ & 7) == rsp_) { + SetSIB(TIMES_1, rsp, base); + } + } else if (IsInt8(disp)) { + SetModRM(1, base); + if ((base_ & 7) == rsp_) { + SetSIB(TIMES_1, rsp, base); + } + SetDisp8(disp); + } else { + SetModRM(2, base); + if ((base_ & 7) == rsp_) { + SetSIB(TIMES_1, rsp, base); + } + SetDisp32(disp); + } + } + + // This addressing mode does not exist. + Address(Register base, Register r); + + Address(Register index, ScaleFactor scale, int32_t disp) { + ASSERT(index.code() != rsp.code()); // Illegal addressing mode. + SetModRM(0, rsp); + SetSIB(scale, index, rbp); + SetDisp32(disp); + } + + // This addressing mode does not exist. + Address(Register index, ScaleFactor scale, Register r); + + Address(Register base, Register index, ScaleFactor scale, int32_t disp) { + ASSERT(index.code() != rsp.code()); // Illegal addressing mode. + int rbp_ = rbp.code(); + if ((disp == 0) && ((base.code() & 7) != rbp_)) { + SetModRM(0, rsp); + SetSIB(scale, index, base); + } else if (IsInt8(disp)) { + SetModRM(1, rsp); + SetSIB(scale, index, base); + SetDisp8(disp); + } else { + SetModRM(2, rsp); + SetSIB(scale, index, base); + SetDisp32(disp); + } + } + + // This addressing mode does not exist. + Address(Register base, Register index, ScaleFactor scale, Register r); + +private: + Address(Register base, int32_t disp, bool fixed) { + ASSERT(fixed); + + SetModRM(2, base); + if ((base.code() & 7) == rsp.code()) { + SetSIB(TIMES_1, rsp, base); + } + SetDisp32(disp); + } +}; + +// --- + +class Assembler : public AssemblerBase { +public: + Assembler(void *address) : AssemblerBase(address) { + buffer_ = new CodeBuffer(); + } + ~Assembler() { + if (buffer_) + delete buffer_; + buffer_ = NULL; + } + +public: + void Emit1(byte_t val) { + buffer_->Emit8(val); + } + + void Emit(int32_t value) { + buffer_->Emit32(value); + } + + void EmitInt64(int64_t value) { + buffer_->Emit64(value); + } + + // --- + + // refer android_art + uint8_t EmitOptionalRex(bool force, bool w, bool r, bool x, bool b) { + // REX.WRXB + // W - 64-bit operand + // R - MODRM.reg + // X - SIB.index + // B - MODRM.rm/SIB.base + + uint8_t rex = force ? 0x40 : 0; + if (w) { + rex |= 0x48; // REX.W000 + } + if (r) { + rex |= 0x44; // REX.0R00 + } + if (x) { + rex |= 0x42; // REX.00X0 + } + if (b) { + rex |= 0x41; // REX.000B + } + if (rex != 0) { + return rex; + } + return 0; + } + + void Emit_64REX(uint8_t extra) { + uint8_t rex = EmitOptionalRex(false, true, false, false, false); + rex |= extra; + if (rex) + Emit1(rex); + } + + void EmitREX_ExtraRegister(Register reg) { + uint8_t rex = EmitOptionalRex(false, reg.size() == 64, reg.code() > 7, false, reg.code() > 7); + if (rex) + Emit1(rex); + } + + void EmitREX_Register(Register reg) { + uint8_t rex = EmitOptionalRex(false, reg.size() == 64, reg.code() > 7, false, false); + if (rex) + Emit1(rex); + } + + void EmitREX_Register_Operand(Register reg, Operand &operand) { + if (reg.size() != 64) + UNIMPLEMENTED(); + uint8_t rex = operand.rex(); + rex |= EmitOptionalRex(true, reg.size() == 64, reg.code() > 7, false, false); + if (rex != 0) { + Emit1(rex); + } + } + + void EmitREX_Operand(Operand &operand) { + uint8_t rex = operand.rex(); + rex |= REX_PREFIX; + if (rex != 0) { + Emit1(rex); + } + } + + // --- + + void EmitImmediate(Immediate imm, int imm_size) { + if (imm_size == 8) { + buffer_->Emit8((uint8_t)imm.value()); + } else if (imm_size == 32) { + buffer_->Emit32((uint32_t)imm.value()); + } else if (imm_size == 64) { + buffer_->Emit64((uint64_t)imm.value()); + } else { + UNREACHABLE(); + } + } + + // --- + + // ATTENTION: + // ModR/M == 8 registers and 24 addressing mode + + void Emit_OpEn_Register_MemOperand(Register dst, Address &operand) { + EmitModRM_Update_Register(operand.modrm(), dst); + buffer_->EmitBuffer(&operand.encoding_[1], operand.length_ - 1); + } + + void Emit_OpEn_Register_RegOperand(Register dst, Register src) { + EmitModRM_Register_Register(dst, src); + } + + void Emit_OpEn_MemOperand_Immediate(uint8_t extra_opcode, Address &operand, Immediate imm) { + EmitModRM_Update_ExtraOpcode(operand.modrm(), extra_opcode); + buffer_->EmitBuffer(&operand.encoding_[1], operand.length_ - 1); + EmitImmediate(imm, imm.size()); + } + + void Emit_OpEn_RegOperand_Immediate(uint8_t extra_opcode, Register reg, Immediate imm) { + EmitModRM_ExtraOpcode_Register(extra_opcode, reg); + EmitImmediate(imm, imm.size()); + } + + void Emit_OpEn_MemOperand(uint8_t extra_opcode, Address &operand) { + EmitModRM_Update_ExtraOpcode(operand.modrm(), extra_opcode); + buffer_->EmitBuffer(&operand.encoding_[1], operand.length_ - 1); + } + + void Emit_OpEn_RegOperand(uint8_t extra_opcode, Register reg) { + EmitModRM_ExtraOpcode_Register(extra_opcode, reg); + } + + // Encoding: OI + void Emit_OpEn_OpcodeRegister_Immediate(uint8_t opcode, Register dst, Immediate imm) { + EmitOpcode_Register(opcode, dst); + EmitImmediate(imm, imm.size()); + } + + // --- + + inline void EmitModRM(uint8_t Mod, uint8_t RegOpcode, uint8_t RM) { + uint8_t ModRM = 0; + ModRM |= Mod << 6; + ModRM |= RegOpcode << 3; + ModRM |= RM; + Emit1(ModRM); + } + + void EmitModRM_ExtraOpcode_Register(uint8_t extra_opcode, Register reg) { + EmitModRM(0b11, extra_opcode, reg.code()); + } + + void EmitModRM_Register_Register(Register reg1, Register reg2) { + EmitModRM(0b11, reg1.code(), reg2.code()); + } + + // update operand's ModRM + void EmitModRM_Update_Register(uint8_t modRM, Register reg) { + EmitModRM(ModRM_Mod(modRM), reg.low_bits(), ModRM_RM(modRM)); + } + + // update operand's ModRM + void EmitModRM_Update_ExtraOpcode(uint8_t modRM, uint8_t extra_opcode) { + EmitModRM(ModRM_Mod(modRM), extra_opcode, ModRM_RM(modRM)); + } + + // --- + + void EmitOpcode(uint8_t opcode) { + Emit1(opcode); + } + + void EmitOpcode_Register(uint8_t opcode, Register reg) { + EmitOpcode(opcode | reg.low_bits()); + } + + // --- + + void pushfq() { + Emit1(0x9C); + } + + void jmp(Immediate imm); + + void sub(Register dst, Immediate imm) { + EmitREX_Register(dst); + + EmitOpcode(0x81); + + Emit_OpEn_RegOperand_Immediate(0x5, dst, imm); + } + + void add(Register dst, Immediate imm) { + EmitREX_Register(dst); + + EmitOpcode(0x81); + + Emit_OpEn_RegOperand_Immediate(0x0, dst, imm); + } + + // MOV RAX, 0x320 + // 48 c7 c0 20 03 00 00 (MI encoding) + // 48 b8 20 03 00 00 00 00 00 00 (OI encoding) + void mov(Register dst, const Immediate imm) { + EmitREX_Register(dst); + + Emit_OpEn_OpcodeRegister_Immediate(0xb8, dst, imm); + } + + void mov(Address dst, const Immediate imm) { + EmitREX_Operand(dst); + + EmitOpcode(0xc7); + + Emit_OpEn_MemOperand_Immediate(0x0, dst, imm); + } + + void mov(Register dst, Address src) { + EmitREX_Register(dst); + + EmitOpcode(0x8B); + + Emit_OpEn_Register_MemOperand(dst, src); + } + + void mov(Address dst, Register src) { + EmitREX_Register_Operand(src, dst); + + EmitOpcode(0x89); + + Emit_OpEn_Register_MemOperand(src, dst); + } + + void mov(Register dst, Register src) { + EmitREX_Register(dst); + + Emit1(0x8B); + + Emit_OpEn_Register_RegOperand(dst, src); + } + + void call(Address operand) { + EmitREX_Operand(operand); + + EmitOpcode(0xFF); + + Emit_OpEn_MemOperand(0x2, operand); + } + + void call(Immediate imm) { + EmitOpcode(0xe8); + + EmitImmediate(imm, imm.size()); + } + + void call(Register reg) { + EmitREX_Register(reg); + + EmitOpcode(0xFF); + + Emit_OpEn_RegOperand(0x2, reg); + } + + void pop(Register reg) { + EmitREX_ExtraRegister(reg); + + EmitOpcode_Register(0x58, reg); + } + + void push(Register reg) { + EmitREX_ExtraRegister(reg); + + EmitOpcode_Register(0x50, reg); + } + + void ret() { + EmitOpcode(0xc3); + } + void nop() { + EmitOpcode(0x90); + } +}; + +// --- + +class TurboAssembler : public Assembler { +public: + TurboAssembler(void *address) : Assembler(address) { + } + + ~TurboAssembler() { + } + + addr64_t CurrentIP(); + + void CallFunction(ExternalReference function) { +#if 0 + mov(r11, Immediate((int64_t)function.address(), 64)); + call(r11); +#endif + + nop(); + MovRipToRegister(VOLATILE_REGISTER); + call(Address(VOLATILE_REGISTER, INT32_MAX)); + { + RelocLabel *addr_label = new RelocLabel((uint64_t)function.address()); + addr_label->link_to(kDisp32_off_9, 0, ip_offset()); + this->AppendRelocLabel(addr_label); + } + nop(); + } + + void MovRipToRegister(Register dst) { + call(Immediate(0, 32)); + pop(dst); + } +}; + +} // namespace x64 +} // namespace zz diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-x86-shared.cc b/app/src/main/cpp/Dobby/source/core/assembler/assembler-x86-shared.cc new file mode 100644 index 0000000..12968ac --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-x86-shared.cc @@ -0,0 +1,17 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32) + +#include "core/assembler/assembler-x86-shared.h" + +using namespace zz::x86shared; + +void Assembler::jmp(Immediate imm) { + buffer_->Emit8(0xE9); + buffer_->Emit32((int)imm.value()); +} + +uint64_t TurboAssembler::CurrentIP() { + return pc_offset() + (addr_t)realized_addr_; +} + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler-x86-shared.h b/app/src/main/cpp/Dobby/source/core/assembler/assembler-x86-shared.h new file mode 100644 index 0000000..d84af57 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler-x86-shared.h @@ -0,0 +1,710 @@ +#ifndef CORE_ASSEMBLER_X64_H +#define CORE_ASSEMBLER_X64_H + +#include "common_header.h" + +#include "core/arch/x64/registers-x64.h" +#include "core/assembler/assembler.h" + +#include "MemoryAllocator/CodeBuffer/code_buffer_x64.h" + +#include "xnucxx/LiteMutableArray.h" +#include "xnucxx/LiteIterator.h" + +#define IsInt8(imm) (-128 <= imm && imm <= 127) + +namespace zz { +namespace x86shared { + +using namespace x64; + +constexpr Register VOLATILE_REGISTER = r11; + +// ================================================================ +// AssemblerPseudoLabel + +class AssemblerPseudoLabel : public Label { +public: + enum PseudoLabelType { kDisp32_off_9 }; + + typedef struct _PseudoLabelInstruction { + int position_; + PseudoLabelType type_; + } PseudoLabelInstruction; + +public: + AssemblerPseudoLabel(void) { + instructions_.initWithCapacity(8); + } + ~AssemblerPseudoLabel(void) { + for (size_t i = 0; i < instructions_.getCount(); i++) { + PseudoLabelInstruction *item = (PseudoLabelInstruction *)instructions_.getObject(i); + delete item; + } + + instructions_.release(); + } + + bool has_confused_instructions() { + return instructions_.getCount() > 0; + } + + void link_confused_instructions(CodeBuffer *buffer = nullptr) { + if (!buffer) + UNREACHABLE(); + CodeBuffer *_buffer = buffer; + + for (size_t i = 0; i < instructions_.getCount(); i++) { + PseudoLabelInstruction *instruction = (PseudoLabelInstruction *)instructions_.getObject(i); + + int32_t offset = pos() - instruction->position_; + + switch (instruction->type_) { + case kDisp32_off_9: { + int disp32_fix_pos = instruction->position_ - sizeof(int32_t); + _buffer->FixBindLabel(disp32_fix_pos, offset + 9); + } break; + default: + UNREACHABLE(); + break; + } + } + }; + + void link_to(int pos, PseudoLabelType type) { + PseudoLabelInstruction *instruction = new PseudoLabelInstruction; + instruction->position_ = pos; + instruction->type_ = type; + instructions_.pushObject((LiteObject *)instruction); + } + +private: + LiteMutableArray instructions_; +}; + +class RelocLabel : public AssemblerPseudoLabel { +public: + explicit RelocLabel(uint64_t data) : data_size_(0) { + data_ = data; + } + + uint64_t data() { + return data_; + } + +private: + uint64_t data_; + + int data_size_; +}; + +#define ModRM_Mod(byte) ((byte & 0b11000000) >> 6) +#define ModRM_RegOpcode(byte) ((byte & 0b00111000) >> 3) +#define ModRM_RM(byte) (byte & 0b00000111) + +typedef union _ModRM { + byte_t ModRM; + struct { + byte_t RM : 3; + byte_t RegOpcode : 3; + byte_t Mod : 2; + }; +} ModRM; + +// ================================================================ +// Immediate + +class Immediate { +public: + explicit Immediate(int64_t imm) : value_(imm), value_size_(64) { + if ((int64_t)(int8_t)imm == imm) { + value_size_ = 8; + } else if ((int64_t)(int16_t)imm == imm) { + value_size_ = 8; + } else if ((int64_t)(int32_t)imm == imm) { + value_size_ = 32; + } else { + value_size_ = 64; + } + } + + explicit Immediate(int64_t imm, int size) : value_(imm), value_size_(size) { + } + + int64_t value() const { + return value_; + } + + int size() const { + return value_size_; + } + +private: + const int64_t value_; + + int value_size_; +}; + +// ================================================================ +// Operand + +class Operand { +public: + // [base] + Operand(Register base); + + // [base + disp/r] + Operand(Register base, int32_t disp); + + // [base + index*scale + disp/r] + Operand(Register base, Register index, ScaleFactor scale, int32_t disp); + + // [index*scale + disp/r] + Operand(Register index, ScaleFactor scale, int32_t disp); + +public: // Getter and Setter + uint8_t rex() const { + return rex_; + } + + inline uint8_t rex_b() const { + return (rex_ & REX_B); + } + + inline uint8_t rex_x() const { + return (rex_ & REX_X); + } + + inline uint8_t rex_r() const { + return (rex_ & REX_R); + } + + inline uint8_t rex_w() const { + return (rex_ & REX_W); + } + + uint8_t modrm() { + return (encoding_at(0)); + } + + uint8_t mod() const { + return (encoding_at(0) >> 6) & 3; + } + + Register rm() const { + int rm_rex = rex_b() << 3; + return Register::from_code(rm_rex + (encoding_at(0) & 7)); + } + + ScaleFactor scale() const { + return static_cast((encoding_at(1) >> 6) & 3); + } + + Register index() const { + int index_rex = rex_x() << 2; + return Register::from_code(index_rex + ((encoding_at(1) >> 3) & 7)); + } + + Register base() const { + int base_rex = rex_b() << 3; + return Register::from_code(base_rex + (encoding_at(1) & 7)); + } + + int8_t disp8() const { + ASSERT(length_ >= 2); + return static_cast(encoding_[length_ - 1]); + } + + int32_t disp32() const { + ASSERT(length_ >= 5); + return static_cast(encoding_[length_ - 4]); + } + +protected: + Operand() : length_(0), rex_(REX_NONE) { + } // Needed by subclass Address. + + void SetModRM(int mod, Register rm) { + ASSERT((mod & ~3) == 0); + + if ((rm.code() > 7) && !((rm.Is(r12)) && (mod != 3))) { + rex_ |= REX_B; + } + encoding_[0] = (mod << 6) | (rm.code() & 7); + length_ = 1; + } + + void SetSIB(ScaleFactor scale, Register index, Register base) { + ASSERT(length_ == 1); + ASSERT((scale & ~3) == 0); + + if (base.code() > 7) { + ASSERT((rex_ & REX_B) == 0); // Must not have REX.B already set. + rex_ |= REX_B; + } + if (index.code() > 7) + rex_ |= REX_X; + encoding_[1] = (scale << 6) | ((index.code() & 7) << 3) | (base.code() & 7); + length_ = 2; + } + + void SetDisp8(int8_t disp) { + ASSERT(length_ == 1 || length_ == 2); + + encoding_[length_++] = static_cast(disp); + } + + void SetDisp32(int32_t disp) { + ASSERT(length_ == 1 || length_ == 2); + + *(int32_t *)&encoding_[length_] = disp; + length_ += sizeof(disp); + } + +private: + // explicit Operand(Register reg) : rex_(REX_NONE) { SetModRM(3, reg); } + + // Get the operand encoding byte at the given index. + uint8_t encoding_at(intptr_t index) const { + ASSERT(index >= 0 && index < length_); + return encoding_[index]; + } + +public: + uint8_t length_; + uint8_t rex_; + uint8_t encoding_[6]; +}; + +// ================================================================ +// Address + +class Address : public Operand { +public: + Address(Register base, int32_t disp) { + int base_ = base.code(); + int rbp_ = rbp.code(); + int rsp_ = rsp.code(); + if ((disp == 0) && ((base_ & 7) != rbp_)) { + SetModRM(0, base); + if ((base_ & 7) == rsp_) { + SetSIB(TIMES_1, rsp, base); + } + } else if (IsInt8(disp)) { + SetModRM(1, base); + if ((base_ & 7) == rsp_) { + SetSIB(TIMES_1, rsp, base); + } + SetDisp8(disp); + } else { + SetModRM(2, base); + if ((base_ & 7) == rsp_) { + SetSIB(TIMES_1, rsp, base); + } + SetDisp32(disp); + } + } + + // This addressing mode does not exist. + Address(Register base, Register r); + + Address(Register index, ScaleFactor scale, int32_t disp) { + ASSERT(index.code() != rsp.code()); // Illegal addressing mode. + SetModRM(0, rsp); + SetSIB(scale, index, rbp); + SetDisp32(disp); + } + + // This addressing mode does not exist. + Address(Register index, ScaleFactor scale, Register r); + + Address(Register base, Register index, ScaleFactor scale, int32_t disp) { + ASSERT(index.code() != rsp.code()); // Illegal addressing mode. + int rbp_ = rbp.code(); + if ((disp == 0) && ((base.code() & 7) != rbp_)) { + SetModRM(0, rsp); + SetSIB(scale, index, base); + } else if (IsInt8(disp)) { + SetModRM(1, rsp); + SetSIB(scale, index, base); + SetDisp8(disp); + } else { + SetModRM(2, rsp); + SetSIB(scale, index, base); + SetDisp32(disp); + } + } + + // This addressing mode does not exist. + Address(Register base, Register index, ScaleFactor scale, Register r); + +private: + Address(Register base, int32_t disp, bool fixed) { + ASSERT(fixed); + SetModRM(2, base); + if ((base.code() & 7) == rsp.code()) { + SetSIB(TIMES_1, rsp, base); + } + SetDisp32(disp); + } +}; + +// ================================================================ +// Assembler + +class Assembler : public AssemblerBase { +public: + Assembler(void *address, int mode) : AssemblerBase(address) : mode_(mode) { + buffer_ = new CodeBuffer(); + } + ~Assembler() { + if (buffer_) + delete buffer_; + buffer_ = NULL + } + +public: + void Emit1(byte_t val) { + buffer_->Emit8(val); + } + + void Emit(int32_t value) { + buffer_->Emit32(value); + } + + void EmitInt64(int64_t value) { + buffer_->Emit64(value); + } + + void EmitAddr(uint64_t addr) { + if (mode == 64) { + EmitInt64(int64_t)addr); + } else { + EmitI((int32_t)addr); + } + } + + // ================================================================ + // REX + + // refer android_art + uint8_t EmitOptionalRex(bool force, bool w, bool r, bool x, bool b) { + // REX.WRXB + // W - 64-bit operand + // R - MODRM.reg + // X - SIB.index + // B - MODRM.rm/SIB.base + + uint8_t rex = force ? 0x40 : 0; + if (w) { + rex |= 0x48; // REX.W000 + } + if (r) { + rex |= 0x44; // REX.0R00 + } + if (x) { + rex |= 0x42; // REX.00X0 + } + if (b) { + rex |= 0x41; // REX.000B + } + if (rex != 0) { + return rex; + } + return 0; + } + + void Emit_64REX(uint8_t extra) { + uint8_t rex = EmitOptionalRex(false, true, false, false, false); + rex |= extra; + if (rex) + Emit1(rex); + } + + void EmitREX_ExtraRegister(Register reg) { + uint8_t rex = EmitOptionalRex(false, reg.size() == 64, reg.code() > 7, false, reg.code() > 7); + if (rex) + Emit1(rex); + } + + void EmitREX_Register(Register reg) { + uint8_t rex = EmitOptionalRex(false, reg.size() == 64, reg.code() > 7, false, false); + if (rex) + Emit1(rex); + } + + void EmitREX_Register_Operand(Register reg, Operand &operand) { + if (reg.size() != 64) + UNIMPLEMENTED(); + uint8_t rex = operand.rex(); + rex |= EmitOptionalRex(true, reg.size() == 64, reg.code() > 7, false, false); + if (rex != 0) { + Emit1(rex); + } + } + + void EmitREX_Operand(Operand &operand) { + uint8_t rex = operand.rex(); + rex |= REX_PREFIX; + if (rex != 0) { + Emit1(rex); + } + } + + // ================================================================ + // Immediate + + void EmitImmediate(Immediate imm, int imm_size) { + if (imm_size == 8) { + buffer_->Emit8((uint8_t)imm.value()); + } else if (imm_size == 32) { + buffer_->Emit32((uint32_t)imm.value()); + } else if (imm_size == 64) { + buffer_->Emit64((uint64_t)imm.value()); + } else { + UNREACHABLE(); + } + } + + // ================================================================ + // Operand Encoding + + // ATTENTION: + // ModR/M == 8 registers and 24 addressing mode + + // RM or MR + void Emit_OpEn_Register_MemOperand(Register dst, Address &operand) { + EmitModRM_Update_Register(operand.modrm(), dst); + buffer_->EmitBuffer(&operand.encoding_[1], operand.length_ - 1); + } + void Emit_OpEn_Register_RegOperand(Register dst, Register src) { + EmitModRM_Register_Register(dst, src); + } + + void Emit_OpEn_MemOperand_Immediate(uint8_t extra_opcode, Address &operand, Immediate imm) { + } + void Emit_OpEn_RegOperand_Immediate(uint8_t extra_opcode, Register reg, Immediate imm) { + EmitModRM_ExtraOpcode_Register(extra_opcode, reg); + EmitImmediate(imm, imm.size()); + } + + void Emit_OpEn_MemOperand(uint8_t extra_opcode, Address &operand) { + EmitModRM_Update_ExtraOpcode(operand.modrm(), extra_opcode); + buffer_->EmitBuffer(&operand.encoding_[1], operand.length_ - 1); + } + void Emit_OpEn_RegOperand(uint8_t extra_opcode, Register reg) { + EmitModRM_ExtraOpcode_Register(extra_opcode, reg); + } + + // Encoding: OI + void Emit_OpEn_OpcodeRegister_Immediate(uint8_t opcode, Register dst, Immediate imm) { + EmitOpcode_Register(opcode, dst); + EmitImmediate(imm, imm.size()); + } + + // ================================================================ + // ModRM + + inline void EmitModRM(uint8_t Mod, uint8_t RegOpcode, uint8_t RM) { + uint8_t ModRM = 0; + ModRM |= Mod << 6; + ModRM |= RegOpcode << 3; + ModRM |= RM; + Emit1(ModRM); + } + + void EmitModRM_ExtraOpcode_Register(uint8_t extra_opcode, Register reg) { + EmitModRM(0b11, extra_opcode, reg.code()); + } + + void EmitModRM_Register_Register(Register reg1, Register reg2) { + EmitModRM(0b11, reg1.code(), reg2.code()); + } + + // update operand's ModRM + void EmitModRM_Update_Register(uint8_t modRM, Register reg) { + EmitModRM(ModRM_Mod(modRM), reg.low_bits(), ModRM_RM(modRM)); + } + + // update operand's ModRM + void EmitModRM_Update_ExtraOpcode(uint8_t modRM, uint8_t extra_opcode) { + EmitModRM(ModRM_Mod(modRM), extra_opcode, ModRM_RM(modRM)); + } + + // ================================================================ + // Opcode + void EmitOpcode(uint8_t opcode) { + Emit1(opcode); + } + + void EmitOpcode_Register(uint8_t opcode, Register reg) { + EmitOpcode(opcode | reg.low_bits()); + } + + // ================================================================ + // Instruction + + void pushfq() { + Emit1(0x9C); + } + + void jmp(Immediate imm); + + void sub(Register dst, Immediate imm) { + EmitREX_Register(dst); + EmitOpcode(0x81); + Emit_OpEn_RegOperand_Immediate(0x5, dst, imm); + } + + void add(Register dst, Immediate imm) { + EmitREX_Register(dst); + EmitOpcode(0x81); + Emit_OpEn_RegOperand_Immediate(0x0, dst, imm); + } + + // MOV RAX, 0x320 + // 48 c7 c0 20 03 00 00 (MI encoding) + // 48 b8 20 03 00 00 00 00 00 00 (OI encoding) + void mov(Register dst, const Immediate imm) { + EmitREX_Register(dst); + + // OI encoding + Emit_OpEn_OpcodeRegister_Immediate(0xb8, dst, imm); + } + + void mov(Register dst, Address src) { + EmitREX_Register(dst); + + EmitOpcode(0x8B); + + Emit_OpEn_Register_MemOperand(dst, src); + } + + void mov(Address dst, Register src) { + EmitREX_Register_Operand(src, dst); + EmitOpcode(0x89); + Emit_OpEn_Register_MemOperand(src, dst); + } + + void mov(Register dst, Register src) { + EmitREX_Register(dst); + + Emit1(0x8B); + + Emit_OpEn_Register_RegOperand(dst, src); + } + + void call(Address operand) { + EmitREX_Operand(operand); + + EmitOpcode(0xFF); + + Emit_OpEn_MemOperand(0x2, operand); + } + + void call(Immediate imm) { + EmitOpcode(0xe8); + EmitImmediate(imm, imm.size()); + } + + void call(Register reg) { + EmitREX_Register(reg); + EmitOpcode(0xFF); + Emit_OpEn_RegOperand(0x2, reg); + } + + void pop(Register reg) { + EmitREX_ExtraRegister(reg); + EmitOpcode_Register(0x58, reg); + } + + void push(Register reg) { + EmitREX_ExtraRegister(reg); + EmitOpcode_Register(0x50, reg); + } + + void ret() { + EmitOpcode(0xc3); + } + void nop() { + EmitOpcode(0x90); + } + +private: + int mode_; +}; + +// ================================================================ +// TurboAssembler + +class TurboAssembler : public Assembler { +public: + TurboAssembler(void *address, int mode) : Assembler(address, mode) { + data_labels_ = NULL; + } + + addr64_t CurrentIP(); + + void CallFunction(ExternalReference function) { +#if 0 + mov(r11, Immediate((int64_t)function.address(), 64)); + call(r11); +#endif + + nop(); + MovRipToRegister(VOLATILE_REGISTER); + call(Address(VOLATILE_REGISTER, INT32_MAX)); + { + RelocLabel *addrLabel = new RelocLabel((uint64_t)function.address()); + addrLabel->link_to(ip_offset(), AssemblerPseudoLabel::kDisp32_off_9); + this->AppendRelocLabel(addrLabel); + } + nop(); + } + + void MovRipToRegister(Register dst) { + call(Immediate(0, 32)); + pop(dst); + } + + // ================================================================ + // RelocLabel + + void PseudoBind(AssemblerPseudoLabel *label) { + const addr_t bound_pc = buffer_->GetBufferSize(); + label->bind_to(bound_pc); + // If some instructions have been wrote, before the label bound, we need link these `confused` instructions + if (label->has_confused_instructions()) { + label->link_confused_instructions(reinterpret_cast(this->GetCodeBuffer())); + } + } + + void RelocBind() { + if (data_labels_ == NULL) + return; + for (size_t i = 0; i < data_labels_->getCount(); i++) { + RelocLabel *label = (RelocLabel *)data_labels_->getObject(i); + PseudoBind(label); + EmitAddr(label->data()); + } + } + + void AppendRelocLabel(RelocLabel *label) { + if (data_labels_ == NULL) { + data_labels_ = new LiteMutableArray(8); + } + data_labels_->pushObject((LiteObject *)label); + } + + LiteMutableArray *GetLabels() { + return data_labels_; + } + +private: + LiteMutableArray *data_labels_; +}; + +} // namespace x86shared +} // namespace zz + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler.cc b/app/src/main/cpp/Dobby/source/core/assembler/assembler.cc new file mode 100644 index 0000000..69c761f --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler.cc @@ -0,0 +1,65 @@ +#include "core/assembler/assembler.h" +#include "logging/logging.h" + +namespace zz { + +const void *ExternalReference::address() { + return address_; +} + +AssemblerBase::AssemblerBase(void *address) { + realized_addr_ = address; + buffer_ = nullptr; +} + +AssemblerBase::~AssemblerBase() { + buffer_ = nullptr; +} + +size_t AssemblerBase::ip_offset() const { + return reinterpret_cast(buffer_)->GetBufferSize(); +} + +size_t AssemblerBase::pc_offset() const { + return reinterpret_cast(buffer_)->GetBufferSize(); +} + +CodeBuffer *AssemblerBase::GetCodeBuffer() { + return buffer_; +} + +void AssemblerBase::PseudoBind(AssemblerPseudoLabel *label) { + off_t bound_offset = reinterpret_cast(buffer_)->GetBufferSize(); + label->bind_to(bound_offset); + // If some instructions had been written, before the label bound, we need link these `confused` instructions + if (label->has_confused_instructions()) { + label->link_confused_instructions(reinterpret_cast(buffer_)); + } +} + +void AssemblerBase::RelocBind() { + for (auto *data_label : data_labels_) { + PseudoBind(data_label); + reinterpret_cast(buffer_)->EmitBuffer(data_label->data_, data_label->data_size_); + } +} + +void AssemblerBase::AppendRelocLabel(RelocLabel *label) { + data_labels_.push_back(label); +} + +void AssemblerBase::SetRealizedAddress(void *address) { + realized_addr_ = address; +} + +void *AssemblerBase::GetRealizedAddress() { + return realized_addr_; +} + +void AssemblerBase::FlushICache(addr_t start, int size) { +} + +void AssemblerBase::FlushICache(addr_t start, addr_t end) { +} + +} // namespace zz diff --git a/app/src/main/cpp/Dobby/source/core/assembler/assembler.h b/app/src/main/cpp/Dobby/source/core/assembler/assembler.h new file mode 100644 index 0000000..6e53f49 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/assembler/assembler.h @@ -0,0 +1,76 @@ +#pragma once + +#include "MemoryAllocator/CodeBuffer/CodeBufferBase.h" + +#include "AssemblerPseudoLabel.h" + +class CodeBuffer; + +namespace zz { + +class ExternalReference { +public: + explicit ExternalReference(void *address) : address_(address) { +#if defined(__APPLE__) && __arm64e__ +#if __has_feature(ptrauth_calls) + address_ = ptrauth_strip(address, ptrauth_key_asia); +#endif +#endif + } + + const void *address(); + +private: + const void *address_; +}; + +class AssemblerBase { +public: + explicit AssemblerBase(void *address); + + ~AssemblerBase(); + + size_t ip_offset() const; + + size_t pc_offset() const; + + CodeBuffer *GetCodeBuffer(); + + void PseudoBind(AssemblerPseudoLabel *label); + + void RelocBind(); + + void AppendRelocLabel(RelocLabel *label); + +protected: + std::vector data_labels_; + +public: + virtual void *GetRealizedAddress(); + + virtual void SetRealizedAddress(void *address); + + static void FlushICache(addr_t start, int size); + + static void FlushICache(addr_t start, addr_t end); + +protected: + CodeBuffer *buffer_; + + void *realized_addr_; +}; + +} // namespace zz + +#if 0 +#include "globals.h" +#if TARGET_ARCH_ARM +#include "core/assembler/assembler-arm.h" +#elif TARGET_ARCH_ARM64 +#include "core/assembler/assembler-arm64.h" +#elif TARGET_ARCH_X64 +#include "core/assembler/assembler-x64.h" +#else +#error "unsupported architecture" +#endif +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm.cc b/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm.cc new file mode 100644 index 0000000..3d9922f --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm.cc @@ -0,0 +1,19 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM) + +#include "core/codegen/codegen-arm.h" + +namespace zz { +namespace arm { + +void CodeGen::LiteralLdrBranch(uint32_t address) { + TurboAssembler *turbo_assembler_ = reinterpret_cast(this->assembler_); +#define _ turbo_assembler_-> + _ ldr(pc, MemOperand(pc, -4)); + turbo_assembler_->GetCodeBuffer()->Emit32((addr_t)address); +} + +} // namespace arm +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm.h b/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm.h new file mode 100644 index 0000000..9f87202 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm.h @@ -0,0 +1,22 @@ +#ifndef CORE_CODEGEN_ARM_H +#define CORE_CODEGEN_ARM_H + +#include "core/codegen/codegen.h" +#include "core/assembler/assembler.h" +#include "core/assembler/assembler-arm.h" + +namespace zz { +namespace arm { + +class CodeGen : public CodeGenBase { +public: + CodeGen(TurboAssembler *turbo_assembler) : CodeGenBase(turbo_assembler) { + } + + void LiteralLdrBranch(uint32_t address); +}; + +} // namespace arm +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm64.cc b/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm64.cc new file mode 100644 index 0000000..41e209e --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm64.cc @@ -0,0 +1,26 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_ARM64) + +#include "dobby_internal.h" +#include "core/codegen/codegen-arm64.h" + +namespace zz { +namespace arm64 { + +void CodeGen::LiteralLdrBranch(uint64_t address) { + auto turbo_assembler_ = reinterpret_cast(this->assembler_); +#define _ turbo_assembler_-> + + auto dst_label = new RelocLabel(address); + turbo_assembler_->AppendRelocLabel(dst_label); + + _ Ldr(TMP_REG_0, dst_label); + _ br(TMP_REG_0); + +#undef _ +} + +} // namespace arm64 +} // namespace zz + +#endif diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm64.h b/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm64.h new file mode 100644 index 0000000..99dafb3 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen-arm64.h @@ -0,0 +1,21 @@ +#ifndef CORE_CODEGEN_ARM64_H +#define CORE_CODEGEN_ARM64_H + +#include "core/codegen/codegen.h" +#include "core/assembler/assembler.h" +#include "core/assembler/assembler-arm64.h" + +namespace zz { +namespace arm64 { + +class CodeGen : public CodeGenBase { +public: + CodeGen(TurboAssembler *turbo_assembler) : CodeGenBase(turbo_assembler) { + } + void LiteralLdrBranch(uint64_t address); +}; + +} // namespace arm64 +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen-ia32.cc b/app/src/main/cpp/Dobby/source/core/codegen/codegen-ia32.cc new file mode 100644 index 0000000..a5eba09 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen-ia32.cc @@ -0,0 +1,23 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_IA32) + +#include "core/codegen/codegen-ia32.h" + +namespace zz { +namespace x86 { + +void CodeGen::JmpNear(uint32_t address) { + TurboAssembler *turbo_assembler_ = reinterpret_cast(this->assembler_); +#define _ turbo_assembler_-> +#define __ turbo_assembler_->GetCodeBuffer()-> + uint32_t currIP = turbo_assembler_->CurrentIP() + 5; + int32_t offset = (int32_t)(address - currIP); + + __ Emit8(0xe9); + __ Emit32(offset); +} + +} // namespace x86 +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen-ia32.h b/app/src/main/cpp/Dobby/source/core/codegen/codegen-ia32.h new file mode 100644 index 0000000..5ad42bc --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen-ia32.h @@ -0,0 +1,22 @@ +#ifndef CORE_CODEGEN_X86_H +#define CORE_CODEGEN_X86_H + +#include "core/codegen/codegen.h" +#include "core/assembler/assembler.h" +#include "core/assembler/assembler-ia32.h" + +namespace zz { +namespace x86 { + +class CodeGen : public CodeGenBase { +public: + CodeGen(TurboAssembler *turbo_assembler) : CodeGenBase(turbo_assembler) { + } + + void JmpNear(uint32_t address); +}; + +} // namespace x86 +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen-x64.cc b/app/src/main/cpp/Dobby/source/core/codegen/codegen-x64.cc new file mode 100644 index 0000000..83c9777 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen-x64.cc @@ -0,0 +1,25 @@ +#include "platform_macro.h" +#if defined(TARGET_ARCH_X64) + +#include "core/codegen/codegen-x64.h" + +namespace zz { +namespace x64 { + +void CodeGen::JmpNearIndirect(addr_t forward_stub_addr) { + TurboAssembler *turbo_assembler_ = reinterpret_cast(this->assembler_); +#define _ turbo_assembler_-> +#define __ turbo_assembler_->GetCodeBuffer()-> + uint64_t currIP = turbo_assembler_->CurrentIP() + 6; + int32_t offset = (int32_t)(forward_stub_addr - currIP); + + // jmp *(rip + disp32) + __ Emit8(0xFF); + __ Emit8(0x25); // ModR/M: 00 100 101 + __ Emit32(offset); +} + +} // namespace x64 +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen-x64.h b/app/src/main/cpp/Dobby/source/core/codegen/codegen-x64.h new file mode 100644 index 0000000..5fbbc1f --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen-x64.h @@ -0,0 +1,22 @@ +#ifndef CORE_CODEGEN_X64_H +#define CORE_CODEGEN_X64_H + +#include "core/codegen/codegen.h" +#include "core/assembler/assembler.h" +#include "core/assembler/assembler-x64.h" + +namespace zz { +namespace x64 { + +class CodeGen : public CodeGenBase { +public: + CodeGen(TurboAssembler *turbo_assembler) : CodeGenBase(turbo_assembler) { + } + + void JmpNearIndirect(addr_t forward_stub_addr); +}; + +} // namespace x64 +} // namespace zz + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/codegen/codegen.h b/app/src/main/cpp/Dobby/source/core/codegen/codegen.h new file mode 100644 index 0000000..e75d193 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/core/codegen/codegen.h @@ -0,0 +1,17 @@ +#ifndef CORE_CODEGEN_H +#define CORE_CODEGEN_H + +#include "core/assembler/assembler.h" + +using namespace zz; + +class CodeGenBase { +public: + CodeGenBase(AssemblerBase *assembler) : assembler_(assembler) { + } + +protected: + AssemblerBase *assembler_; +}; + +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/core/emulator/dummy.cc b/app/src/main/cpp/Dobby/source/core/emulator/dummy.cc new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/cpp/Dobby/source/dobby.cpp b/app/src/main/cpp/Dobby/source/dobby.cpp new file mode 100644 index 0000000..2026830 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/dobby.cpp @@ -0,0 +1,32 @@ +#include "dobby_internal.h" +#include "Interceptor.h" + +__attribute__((constructor)) static void ctor() { + DLOG(-1, "================================"); + DLOG(-1, "Dobby"); + DLOG(-1, "================================"); + + DLOG(-1, "dobby in debug log mode, disable with cmake flag \"-DDOBBY_DEBUG=OFF\""); +} + +PUBLIC const char *DobbyGetVersion() { + return __DOBBY_BUILD_VERSION__; +} + +PUBLIC int DobbyDestroy(void *address) { +#if defined(TARGET_ARCH_ARM) + if ((addr_t)address % 2) { + address = (void *)((addr_t)address - 1); + } +#endif + auto entry = Interceptor::SharedInstance()->find((addr_t)address); + if (entry) { + uint8_t *buffer = entry->origin_insns; + uint32_t buffer_size = entry->origin_insn_size; + DobbyCodePatch(address, buffer, buffer_size); + Interceptor::SharedInstance()->remove((addr_t)address); + return RT_SUCCESS; + } + + return RT_FAILED; +} diff --git a/app/src/main/cpp/Dobby/source/dobby_internal.h b/app/src/main/cpp/Dobby/source/dobby_internal.h new file mode 100644 index 0000000..0dc0c13 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/dobby_internal.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common_header.h" + +#include "dobby.h" + +#include "logging/logging.h" +#include "logging/check_logging.h" + +#include "UnifiedInterface/platform.h" + +#include "PlatformUnifiedInterface/MemoryAllocator.h" +#include "PlatformUnifiedInterface/ExecMemory/CodePatchTool.h" +#include "PlatformUnifiedInterface/ExecMemory/ClearCacheTool.h" + +#include "MemoryAllocator/AssemblyCodeBuilder.h" + +#include "InterceptRouting/InterceptRouting.h" diff --git a/app/src/main/cpp/Dobby/source/include/common_header.h b/app/src/main/cpp/Dobby/source/include/common_header.h new file mode 100644 index 0000000..324d144 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/include/common_header.h @@ -0,0 +1,9 @@ +#pragma once + +#include "include/type_header.h" +#include "include/platform_header.h" +#include "include/platform_macro.h" +#include "include/utility_macro.h" + +#include "logging/logging.h" +#include "logging/check_logging.h" \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/include/kernel_mode_header.h b/app/src/main/cpp/Dobby/source/include/kernel_mode_header.h new file mode 100644 index 0000000..66d7a1a --- /dev/null +++ b/app/src/main/cpp/Dobby/source/include/kernel_mode_header.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *vm_map_entry_t; +extern vm_map_t kernel_map; + +typedef void *pmap_paddr_t; +struct pmap; +typedef struct pmap *pmap_t; +extern pmap_t kernel_pmap; + +extern task_t kernel_task; + +#ifdef __cplusplus +} +#endif + +// ----- pmap ----- + +typedef void *pmap_paddr_t; +struct pmap; +typedef struct pmap *pmap_t; + +typedef uint64_t vaddr_t; +typedef uint64_t paddr_t; + +struct pmap; +typedef struct pmap *pmap_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern pmap_t kernel_pmap; + +void pmap_kit_init(); + +paddr_t pmap_kit_kvtophys(pmap_t pmap, vaddr_t va); + +int pmap_kit_set_perm(pmap_t pmap, vaddr_t start, vaddr_t end, unsigned int prot); + +#define cppvPsnk 1 +#define cppvPsrc 2 +void pmap_kit_bcopy_phys(paddr_t src, paddr_t dst, size_t size, int flags); + +typedef uint64_t pt_entry_t; +pt_entry_t pmap_kit_kva_to_pte(pmap_t pmap, vaddr_t va); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/include/list_c.h b/app/src/main/cpp/Dobby/source/include/list_c.h new file mode 100644 index 0000000..2d179d2 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/include/list_c.h @@ -0,0 +1,52 @@ +#pragma once + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; +#define container_of(ptr, type, member) \ + ({ \ + const __typeof(((type *)0)->member) *__mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); \ + }) + +#define INIT_LIST_HEAD(ptr) \ + do { \ + (ptr)->next = (ptr); \ + (ptr)->prev = (ptr); \ + } while (0) + +static inline int list_empty(struct list_head *head) { + return head->next == head; +} + +static void __list_add(struct list_head *new_node, struct list_head *prev, struct list_head *next) { + next->prev = new_node; + new_node->next = next; + new_node->prev = prev; + prev->next = new_node; +} + +static inline void list_add(struct list_head *new_node, struct list_head *head) { + __list_add(new_node, head, head->next); +} + +static inline void __list_del(struct list_head *prev, struct list_head *next) { + next->prev = prev; + prev->next = next; +} + +static inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +#define list_entry(ptr, type, member) container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) list_entry((ptr)->next, type, member) + +#define list_next_entry(pos, member) list_entry((pos)->member.next, typeof(*(pos)), member) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); &pos->member != (head); pos = list_next_entry(pos, member)) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/include/platform_header.h b/app/src/main/cpp/Dobby/source/include/platform_header.h new file mode 100644 index 0000000..c9b8d7f --- /dev/null +++ b/app/src/main/cpp/Dobby/source/include/platform_header.h @@ -0,0 +1,52 @@ +#pragma once + +#if defined(__APPLE__) && __arm64e__ +#if __has_feature(ptrauth_calls) +#include +#endif +#endif + +#if defined(BUILDING_KERNEL) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#endif + +#if defined(BUILDING_KERNEL) +#include "kernel_mode_header.h" +#endif + +#if defined(BUILDING_KERNEL) +#define abs(a) ((a) < 0 ? -(a) : (a)) +#define llabs(a) (((long long)a) < 0 ? -((long long)a) : ((long long)a)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#ifdef __cplusplus +#define abs(a) ((a) < 0 ? -(a) : (a)) +#endif +#else +#ifdef __cplusplus +#include +#include +#include +#include "TINYSTL/vector.h" +#include "TINYSTL/unordered_map.h" +#endif +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/source/include/platform_macro.h b/app/src/main/cpp/Dobby/source/include/platform_macro.h new file mode 100644 index 0000000..300c759 --- /dev/null +++ b/app/src/main/cpp/Dobby/source/include/platform_macro.h @@ -0,0 +1,15 @@ +#pragma once + +#if !defined(DISABLE_ARCH_DETECT) +#if defined(__arm__) +#define TARGET_ARCH_ARM 1 +#elif defined(__arm64__) || defined(__aarch64__) +#define TARGET_ARCH_ARM64 1 +#elif defined(_M_IX86) || defined(__i386__) +#define TARGET_ARCH_IA32 1 +#elif defined(_M_X64) || defined(__x86_64__) +#define TARGET_ARCH_X64 1 +#else +#error Target architecture was not detected as supported by Dobby +#endif +#endif diff --git a/app/src/main/cpp/Dobby/source/include/type_header.h b/app/src/main/cpp/Dobby/source/include/type_header.h new file mode 100644 index 0000000..9c3952c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/include/type_header.h @@ -0,0 +1,14 @@ +#pragma once + +#include "platform_header.h" + +typedef uintptr_t vmaddr_t; +typedef uintptr_t addr_t; +typedef uint32_t addr32_t; +typedef uint64_t addr64_t; +typedef unsigned char byte_t; +typedef unsigned int uint; + +#ifndef NULL +#define NULL 0 +#endif diff --git a/app/src/main/cpp/Dobby/source/include/utility_macro.h b/app/src/main/cpp/Dobby/source/include/utility_macro.h new file mode 100644 index 0000000..a6c567c --- /dev/null +++ b/app/src/main/cpp/Dobby/source/include/utility_macro.h @@ -0,0 +1,62 @@ +#pragma once + +// offset of struct member +#define OFFSETOF(TYPE, ELEMENT) ((size_t) & (((TYPE *)0)->ELEMENT)) + +// assert +#define ASSERT(X) + +// left/right shift +#define LeftShift(a, b, c) ((a & ((1 << b) - 1)) << c) +#define RightShift(a, b, c) ((a >> c) & ((1 << b) - 1)) + +// align +#ifndef ALIGN +#define ALIGN ALIGN_FLOOR +#endif +#define ALIGN_FLOOR(address, range) ((uintptr_t)address & ~((uintptr_t)range - 1)) +#define ALIGN_CEIL(address, range) (((uintptr_t)address + (uintptr_t)range - 1) & ~((uintptr_t)range - 1)) + +// borrow from gdb, refer: binutils-gdb/gdb/arch/arm.h +#define submask(x) ((1L << ((x) + 1)) - 1) +#define bits(obj, st, fn) (((obj) >> (st)) & submask((fn) - (st))) +#define bit(obj, st) (((obj) >> (st)) & 1) +#define sbits(obj, st, fn) ((long)(bits(obj, st, fn) | ((long)bit(obj, fn) * ~submask(fn - st)))) + +// make it easy +#define set_bit(obj, st, bit) obj = (((~(1 << st)) & obj) | (bit << st)) +#define set_bits(obj, st, fn, bits) obj = (((~(submask(fn - st) << st)) & obj) | (bits << st)) + +// definition to expand macro then apply to pragma message +// #pragma message(VAR_NAME_VALUE(HOST_OS_IOS)) +#define VALUE_TO_STRING(x) #x +#define VALUE(x) VALUE_TO_STRING(x) +#define VAR_NAME_VALUE(var) #var "=" VALUE(var) + +// format print +#ifdef __LP64__ +#define __PRI_64_prefix "l" +#define __PRI_PTR_prefix "l" +#else +#define __PRI_64_prefix "ll" +#define __PRI_PTR_prefix +#endif +#define PRIxPTR __PRI_PTR_prefix "x" /* uintptr_t */ + +// deprecated declared +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED +#endif + +// export method +#if defined(_WIN32) +#define PUBLIC +#else +#define PUBLIC __attribute__((visibility("default"))) +#define INTERNAL __attribute__((visibility("internal"))) +#endif \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/tests/CMakeLists.txt b/app/src/main/cpp/Dobby/tests/CMakeLists.txt new file mode 100644 index 0000000..8cb2454 --- /dev/null +++ b/app/src/main/cpp/Dobby/tests/CMakeLists.txt @@ -0,0 +1,120 @@ + +find_package(PkgConfig REQUIRED) +pkg_check_modules(CAPSTONE REQUIRED capstone) +message(STATUS "Capstone libraries: " ${CAPSTONE_LIBRARY_DIRS}) +message(STATUS "Capstone includes: " ${CAPSTONE_INCLUDE_DIRS}) + +pkg_check_modules(UNICORN REQUIRED unicorn) +message(STATUS "unicorn libraries: " ${UNICORN_LIBRARY_DIRS}) +message(STATUS "unicorn includes: " ${UNICORN_INCLUDE_DIRS}) + +get_property(DOBBY_SOURCE_FILE_LIST + TARGET dobby + PROPERTY SOURCES) + +set(DOBBY_SOURCES) +foreach (path ${DOBBY_SOURCE_FILE_LIST}) + if (NOT path MATCHES "^/") + list(APPEND DOBBY_SOURCES ${DOBBY_DIR}/${path}) + else () + list(APPEND DOBBY_SOURCES ${path}) + endif () +endforeach () + + +add_executable(test_insn_relo_arm64 + test_insn_relo_arm64.cpp + UniconEmulator.cpp + ${DOBBY_SOURCES} + ) + +target_compile_definitions(test_insn_relo_arm64 PUBLIC + LOGGING_DEBUG=1 + DISABLE_ARCH_DETECT=1 + TARGET_ARCH_ARM64=1 + TEST_WITH_UNICORN=1 + ) + +target_include_directories(test_insn_relo_arm64 PUBLIC + ${CAPSTONE_INCLUDE_DIRS} + ${UNICORN_INCLUDE_DIRS} + ) + +target_link_directories(test_insn_relo_arm64 PUBLIC + ${CAPSTONE_LIBRARY_DIRS} + ${UNICORN_LIBRARY_DIRS} + ) + +target_link_libraries(test_insn_relo_arm64 PUBLIC + ${CAPSTONE_LIBRARIES} + ${UNICORN_LIBRARIES} + ) + +# --- + +add_executable(test_insn_relo_arm + test_insn_relo_arm.cpp + UniconEmulator.cpp + ${DOBBY_SOURCES} + ) + +target_compile_definitions(test_insn_relo_arm PUBLIC + LOGGING_DEBUG=1 + DISABLE_ARCH_DETECT=1 + TARGET_ARCH_ARM=1 + TEST_WITH_UNICORN=1 + ) + +target_include_directories(test_insn_relo_arm PUBLIC + ${CAPSTONE_INCLUDE_DIRS} + ${UNICORN_INCLUDE_DIRS} + ) + +target_link_directories(test_insn_relo_arm PUBLIC + ${CAPSTONE_LIBRARY_DIRS} + ${UNICORN_LIBRARY_DIRS} + ) + +target_link_libraries(test_insn_relo_arm PUBLIC + ${CAPSTONE_LIBRARIES} + ${UNICORN_LIBRARIES} + ) + +# --- + +add_executable(test_insn_relo_x64 + test_insn_relo_x64.cpp + UniconEmulator.cpp + ${DOBBY_SOURCES} + ) + +target_compile_definitions(test_insn_relo_x64 PUBLIC + LOGGING_DEBUG=1 + DISABLE_ARCH_DETECT=1 + TARGET_ARCH_X64=1 + TEST_WITH_UNICORN=1 + # TARGET_ARCH_IA32=1 + ) + +target_include_directories(test_insn_relo_x64 PUBLIC + ${CAPSTONE_INCLUDE_DIRS} + ${UNICORN_INCLUDE_DIRS} + ) + +target_link_directories(test_insn_relo_x64 PUBLIC + ${CAPSTONE_LIBRARY_DIRS} + ${UNICORN_LIBRARY_DIRS} + ) + +target_link_libraries(test_insn_relo_x64 PUBLIC + ${CAPSTONE_LIBRARIES} + ${UNICORN_LIBRARIES} + ) + +# --- + +add_executable(test_native + test_native.cpp) + +target_link_libraries(test_native + dobby) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/tests/UniconEmulator.cpp b/app/src/main/cpp/Dobby/tests/UniconEmulator.cpp new file mode 100644 index 0000000..a0848ca --- /dev/null +++ b/app/src/main/cpp/Dobby/tests/UniconEmulator.cpp @@ -0,0 +1,219 @@ +#include "UniconEmulator.h" +#include "PlatformUnifiedInterface/MemoryAllocator.h" +#include "InstructionRelocation/InstructionRelocation.h" + +// align +#ifndef ALIGN +#define ALIGN ALIGN_FLOOR +#endif +#define ALIGN_FLOOR(address, range) ((uintptr_t)address & ~((uintptr_t)range - 1)) +#define ALIGN_CEIL(address, range) (((uintptr_t)address + (uintptr_t)range - 1) & ~((uintptr_t)range - 1)) + +std::string g_arch = ""; + +void set_global_arch(std::string arch) { + g_arch = arch; +} + +std::unordered_map CapstoneDisassembler::instances_; + +CapstoneDisassembler *CapstoneDisassembler::Get(const std::string &arch) { + if (instances_.count(arch) == 0) { + cs_err err = CS_ERR_OK; + csh csh_; + if (arch == "arm") { + err = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &csh_); + } else if (arch == "thumb") { + err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB, &csh_); + } else if (arch == "arm64") { + err = cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &csh_); + } else if (arch == "x86_64") { + err = cs_open(CS_ARCH_X86, CS_MODE_64, &csh_); + } else if (arch == "x86") { + err = cs_open(CS_ARCH_X86, CS_MODE_32, &csh_); + } + + auto instance = new CapstoneDisassembler(arch, csh_); + instances_[arch] = instance; + } + return instances_[arch]; +} + +CapstoneDisassembler::CapstoneDisassembler(const std::string &arch, csh csh_) : arch_(arch), csh_(csh_) { +} + +CapstoneDisassembler::~CapstoneDisassembler() { + cs_close((csh *)&csh_); +} + +void CapstoneDisassembler::disassemble(uintptr_t addr, char *buffer, size_t buffer_size) { + cs_insn *insns; + + size_t count = cs_disasm(csh_, (uint8_t *)buffer, buffer_size, addr, 0, &insns); + for (size_t i = 0; i < count; ++i) { + auto &insn = insns[i]; + if (arch_ == "thumb") { + printf("%s %p: %s %s // thumb-%d\n", "-", insn.address, insn.mnemonic, insn.op_str, insn.size / 2); + } else { + printf("%s %p: %s %s\n", "-", insn.address, insn.mnemonic, insn.op_str); + } + } + cs_free(insns, count); +} + +static void hook_trace_insn(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + auto emu = (UniconEmulator *)user_data; + + uc_err err; + char insn_bytes[16]; + err = uc_mem_read(uc, address, insn_bytes, size); + assert(err == UC_ERR_OK); + + if (address >= emu->end_) { + emu->stop(); + return; + } + + if ((emu->arch_ == "arm" || emu->arch_ == "thumb") && emu->isThumb()) { + CapstoneDisassembler::Get("thumb")->disassemble(address, (char *)insn_bytes, size); + } else { + CapstoneDisassembler::Get(g_arch)->disassemble(address, (char *)insn_bytes, size); + } +} + +static void hook_unmapped(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { + printf(">>> Unmapped memory access at %p, data size = %p, data value = %p\n", address, size, value); + auto emu = (UniconEmulator *)user_data; + emu->setUnmappedAddr(address); + emu->stop(); +} + +void dump_regions(uc_engine *uc) { + uc_mem_region *regions; + uint32_t region_count; + uc_mem_regions(uc, ®ions, ®ion_count); + for (int i = 0; i < region_count; ++i) { + auto ®ion = regions[i]; + printf("region: %p - %p\n", region.begin, region.end); + } +} + +UniconEmulator::UniconEmulator(const std::string &arch) { + uc_err err = UC_ERR_OK; + if (arch == "arm" || arch == "thumb") { + err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc_); + } else if (arch == "arm64") { + err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc_); + } else if (arch == "x86_64") { + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc_); + } else if (arch == "x86") { + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc_); + } + assert(err == UC_ERR_OK); + + arch_ = arch; + + uc_hook hook_trace_insn_handle; + uc_hook_add(uc_, &hook_trace_insn_handle, UC_HOOK_CODE, (void *)hook_trace_insn, this, 1, 0); + + uc_hook hook_unmapped_handle; + uc_hook_add(uc_, &hook_unmapped_handle, UC_HOOK_MEM_UNMAPPED, (void *)hook_unmapped, this, 1, 0); +} + +void UniconEmulator::mapMemory(uintptr_t addr, char *buffer, size_t buffer_size) { + uc_err err = UC_ERR_OK; + uintptr_t map_addr = ALIGN_FLOOR(addr, 0x1000); + size_t map_size = ALIGN_CEIL(buffer_size, 0x1000); + err = uc_mem_map(uc_, map_addr, map_size, UC_PROT_ALL); + assert(err == UC_ERR_OK); + err = uc_mem_write(uc_, addr, buffer, buffer_size); + assert(err == UC_ERR_OK); +} + +void *UniconEmulator::readRegister(int regId) { + void *value = nullptr; + uc_reg_read(uc_, regId, &value); + return value; +} + +void UniconEmulator::writeRegister(int regNdx, void *value) { + uc_reg_write(uc_, regNdx, (void *)&value); +} + +void UniconEmulator::start(uintptr_t addr, uintptr_t end) { + uc_err err; + if (g_arch == "thumb") { + addr |= 1; + } + err = uc_emu_start(uc_, addr, end, 0, 0); + if (err == UC_ERR_FETCH_UNMAPPED || err == UC_ERR_READ_UNMAPPED || err == UC_ERR_WRITE_UNMAPPED) + err = UC_ERR_OK; + assert(err == UC_ERR_OK); +} + +void UniconEmulator::emulate(uintptr_t addr, uintptr_t end, char *buffer, size_t buffer_size) { + uc_err err; + mapMemory(addr, buffer, buffer_size); + writeRegister(UC_ARM_REG_PC, (void *)addr); + + if (end == 0) + end = addr + buffer_size; + + start_ = addr; + end_ = end; + + start(addr, end); +} + +void check_insn_relo(char *buffer, size_t buffer_size, bool check_fault_addr, int check_reg_id, + void (^callback)(UniconEmulator *orig, UniconEmulator *relo), uintptr_t relo_stop_size) { + auto *orig_ue = new UniconEmulator(g_arch); + auto *relo_ue = new UniconEmulator(g_arch); + + addr_t orig_addr = 0x100014000; + addr_t relocate_addr = 0x100024000; + + if (g_arch == "arm" || g_arch == "thumb") { + orig_addr = 0x10014000; + relocate_addr = 0x10024000; + } + + // auto dism = CapstoneDisassembler::Get("arm64"); + // dism->disassemble((uintptr_t)orig_addr, buffer, buffer_size); + // printf("\n"); + + auto origin = new CodeMemBlock(orig_addr, buffer_size); + auto relocated = new CodeMemBlock(relocate_addr, 0x1000); + if (g_arch == "thumb") { + origin->reset(origin->addr + 1, origin->size); + } + + GenRelocateCode(buffer, origin, relocated, false); + + if (g_arch == "thumb") { + orig_ue->writeRegister(UC_ARM_REG_CPSR, (void *)0x20); + relo_ue->writeRegister(UC_ARM_REG_CPSR, (void *)0x20); + } + orig_ue->emulate(orig_addr, 0, buffer, buffer_size); + if (g_arch == "thumb") { + relocated->addr -= 1; + } + if (relo_stop_size == 0) { + relo_stop_size = relocated->size; + } + relo_ue->emulate(relocate_addr, relocate_addr + relo_stop_size, (char *)relocated->addr, relocated->size); + + // dism->disassemble((uintptr_t)relocate_addr, (char *)relocated->addr, relocated->size); + // printf("\n"); + + if (check_fault_addr) { + assert(orig_ue->getFaultAddr() == relo_ue->getFaultAddr()); + } else if (check_reg_id != -1) { + assert(orig_ue->readRegister(check_reg_id) == relo_ue->readRegister(check_reg_id)); + } else if (callback) { + callback(orig_ue, relo_ue); + } + + delete orig_ue; + delete relo_ue; +} diff --git a/app/src/main/cpp/Dobby/tests/UniconEmulator.h b/app/src/main/cpp/Dobby/tests/UniconEmulator.h new file mode 100644 index 0000000..414618b --- /dev/null +++ b/app/src/main/cpp/Dobby/tests/UniconEmulator.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +#include +#include + +class CapstoneDisassembler { +public: + void disassemble(uintptr_t addr, char *buffer, size_t buffer_size); + + static CapstoneDisassembler *Get(const std::string &arch); + +private: + CapstoneDisassembler(const std::string &arch, csh csh_); + + ~CapstoneDisassembler(); + +private: + std::string arch_; + csh csh_; + + static std::unordered_map instances_; +}; + +class UniconEmulator { +public: + UniconEmulator(const std::string &arch); + + void mapMemory(uintptr_t addr, char *buffer, size_t buffer_size); + + void *readRegister(int regId); + + void writeRegister(int regId, void *value); + + void start(uintptr_t addr, uintptr_t end); + + void stop() { + uc_emu_stop(uc_); + } + + void emulate(uintptr_t addr, uintptr_t end, char *buffer, size_t buffer_size); + + void setUnmappedAddr(uintptr_t addr) { + unmapped_addr_ = addr; + } + + intptr_t getFaultAddr() { + return unmapped_addr_; + } + + bool isThumb() { + void *reg_value = readRegister(UC_ARM_REG_CPSR); + return (intptr_t)reg_value & 0x20; + } + + void reset(); + +public: + std::string arch_; + uintptr_t start_, end_; + +private: + uc_err err_; + uc_engine *uc_; + uintptr_t unmapped_addr_; +}; + +void set_global_arch(std::string arch); + +void check_insn_relo(char *buffer, size_t buffer_size, bool check_fault_addr, int check_reg_id, + void (^callback)(UniconEmulator *orig, UniconEmulator *relo), uintptr_t relo_stop_size = 0); \ No newline at end of file diff --git a/app/src/main/cpp/Dobby/tests/test_insn_decoder_x86.cpp b/app/src/main/cpp/Dobby/tests/test_insn_decoder_x86.cpp new file mode 100644 index 0000000..20e0fb9 --- /dev/null +++ b/app/src/main/cpp/Dobby/tests/test_insn_decoder_x86.cpp @@ -0,0 +1,267 @@ +#include "InstructionRelocation/InstructionRelocation.h" +#include "InstructionRelocation/arm64/InstructionRelocationARM64.h" + +#include +#include + +#include + +class CapstoneDisassembler { +public: + void disassemble(uintptr_t addr, char *buffer, size_t buffer_szie); + + static CapstoneDisassembler *Get(const std::string &arch); + +private: + CapstoneDisassembler(const std::string &arch, csh csh_); + + ~CapstoneDisassembler(); + +private: + csh csh_; + + static CapstoneDisassembler *instance_; +}; + +CapstoneDisassembler *CapstoneDisassembler::instance_ = nullptr; + +CapstoneDisassembler *CapstoneDisassembler::Get(const std::string &arch) { + if (instance_ == nullptr) { + cs_err err = CS_ERR_OK; + csh csh_; + if (arch == "arm") { + err = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &csh_); + } else if (arch == "arm64") { + err = cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &csh_); + } else if (arch == "x86_64") { + err = cs_open(CS_ARCH_X86, CS_MODE_64, &csh_); + } else if (arch == "x86") { + err = cs_open(CS_ARCH_X86, CS_MODE_32, &csh_); + } + instance_ = new CapstoneDisassembler(arch, csh_); + } + return instance_; +} + +CapstoneDisassembler::CapstoneDisassembler(const std::string &arch, csh csh_) : csh_(csh_) { +} + +CapstoneDisassembler::~CapstoneDisassembler() { + cs_close((csh *)&csh_); +} + +void CapstoneDisassembler::disassemble(uintptr_t addr, char *buffer, size_t buffer_size) { + cs_insn *insns; + + size_t count = cs_disasm(csh_, (uint8_t *)buffer, buffer_size, addr, 0, &insns); + for (size_t i = 0; i < count; ++i) { + auto &insn = insns[i]; + printf("%s %p: %s %s\n", "-", insn.address, insn.mnemonic, insn.op_str); + } + cs_free(insns, count); +} + +class UniconEmulator { +public: + UniconEmulator(const std::string &arch); + + void mapMemory(uintptr_t addr, char *buffer, size_t buffer_size); + + void *readRegister(int regId); + + void writeRegister(int regId, void *value); + + void start(uintptr_t addr, uintptr_t end); + + void stop() { + uc_emu_stop(uc_); + } + + void emulate(uintptr_t addr, char *buffer, size_t buffer_size); + + void setUnmappedAddr(uintptr_t addr) { + unmapped_addr_ = addr; + } + + intptr_t getFaultAddr() { + return unmapped_addr_; + } + + void reset(); + +private: +private: + uc_err err_; + uc_engine *uc_; + uintptr_t unmapped_addr_; +}; + +static void hook_trace_insn(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + auto emu = (UniconEmulator *)user_data; + uc_err err; + char insn_bytes[16]; + err = uc_mem_read(uc, address, insn_bytes, size); + assert(err == UC_ERR_OK); + CapstoneDisassembler::Get("arm64")->disassemble(address, (char *)insn_bytes, size); +} + +static void hook_unmapped(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { + printf(">>> Unmapped memory access at %p, data size = %p, data value = %p\n", address, size, value); + auto emu = (UniconEmulator *)user_data; + emu->setUnmappedAddr(address); + emu->stop(); +} + +void dump_regions(uc_engine *uc) { + uc_mem_region *regions; + uint32_t region_count; + uc_mem_regions(uc, ®ions, ®ion_count); + for (int i = 0; i < region_count; ++i) { + auto ®ion = regions[i]; + printf("region: %p - %p\n", region.begin, region.end); + } +} + +UniconEmulator::UniconEmulator(const std::string &arch) { + uc_err err = UC_ERR_OK; + if (arch == "arm") { + err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc_); + } else if (arch == "arm64") { + err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc_); + } else if (arch == "x86_64") { + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc_); + } else if (arch == "x86") { + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc_); + } + assert(err == UC_ERR_OK); + + uc_hook hook_trace_insn_handle; + uc_hook_add(uc_, &hook_trace_insn_handle, UC_HOOK_CODE, (void *)hook_trace_insn, this, 1, 0); + + uc_hook hook_unmapped_handle; + uc_hook_add(uc_, &hook_unmapped_handle, UC_HOOK_MEM_UNMAPPED, (void *)hook_unmapped, this, 1, 0); +} + +void UniconEmulator::mapMemory(uintptr_t addr, char *buffer, size_t buffer_size) { + uc_err err = UC_ERR_OK; + uintptr_t map_addr = ALIGN_FLOOR(addr, 0x1000); + size_t map_size = ALIGN_CEIL(buffer_size, 0x1000); + err = uc_mem_map(uc_, map_addr, map_size, UC_PROT_ALL); + assert(err == UC_ERR_OK); + err = uc_mem_write(uc_, addr, buffer, buffer_size); + assert(err == UC_ERR_OK); +} + +void *UniconEmulator::readRegister(int regId) { + void *value = nullptr; + uc_reg_read(uc_, regId, &value); + return value; +} + +void UniconEmulator::writeRegister(int regNdx, void *value) { + uc_reg_write(uc_, regNdx, (void *)&value); +} + +void UniconEmulator::start(uintptr_t addr, uintptr_t end) { + uc_err err; + err = uc_emu_start(uc_, addr, end, 0, 0); + if (err == UC_ERR_FETCH_UNMAPPED || err == UC_ERR_READ_UNMAPPED || err == UC_ERR_WRITE_UNMAPPED) + err = UC_ERR_OK; + assert(err == UC_ERR_OK); +} + +void UniconEmulator::emulate(uintptr_t addr, char *buffer, size_t buffer_size) { + uc_err err; + mapMemory(addr, buffer, buffer_size); + writeRegister(UC_ARM_REG_PC, (void *)addr); + start(addr, addr + buffer_size); +} + +void check_insn_relo(char *buffer, size_t buffer_size, bool check_fault_addr, int check_reg_id, + void (^callback)(UniconEmulator *orig, UniconEmulator *relo)) { + auto *orig_ue = new UniconEmulator("arm64"); + auto *relo_ue = new UniconEmulator("arm64"); + + addr_t orig_addr = 0x100004000; + addr_t relocate_addr = 0x200004000; + + // auto dism = CapstoneDisassembler::Get("arm64"); + // dism->disassemble((uintptr_t)orig_addr, buffer, buffer_size); + // printf("\n"); + + auto origin = new CodeMemBlock(orig_addr, buffer_size); + auto relocated = new CodeMemBlock(); + + GenRelocateCode(buffer, origin, relocated, false); + + orig_ue->emulate(orig_addr, buffer, buffer_size); + relo_ue->emulate(relocate_addr, (char *)relocated->addr, relocated->size); + + // dism->disassemble((uintptr_t)relocate_addr, (char *)relocated->addr, relocated->size); + // printf("\n"); + + if (check_fault_addr) { + assert(orig_ue->getFaultAddr() == relo_ue->getFaultAddr()); + } else if (check_reg_id != -1) { + assert(orig_ue->readRegister(check_reg_id) == relo_ue->readRegister(check_reg_id)); + } else if (callback) { + callback(orig_ue, relo_ue); + } + + delete orig_ue; + delete relo_ue; +} + +int main() { + // b #-0x4000 + check_insn_relo("\x00\xf0\xff\x17", 4, true, -1, nullptr); + // b #0x4000 + check_insn_relo("\x00\x10\x00\x14", 4, true, -1, nullptr); + + // bl #-0x4000 + check_insn_relo("\x00\xf0\xff\x97", 4, true, -1, nullptr); + // bl #0x4000 + check_insn_relo("\x00\x10\x00\x94", 4, true, -1, nullptr); + + // mov x0, #0 + // cbz x0, #-0x4000 + check_insn_relo("\x00\x00\x80\xd2\x00\x00\xfe\xb4", 8, true, -1, nullptr); + // mov x0, #0 + // cbz x0, #0x4000 + check_insn_relo("\x00\x00\x80\xd2\x00\x00\x02\xb4", 8, true, -1, nullptr); + + // ldr x0, #-0x4000 + check_insn_relo("\x00\x00\xfe\x58", 4, true, -1, nullptr); + // ldr x0, #0x4000 + check_insn_relo("\x00\x00\x02\x58", 4, true, -1, nullptr); + + // adr x0, #-0x4000 + check_insn_relo("\x00\x00\xfe\x10", 4, false, UC_ARM64_REG_X0, nullptr); + // adr x0, #0x4000 + check_insn_relo("\x00\x00\x02\x10", 4, false, UC_ARM64_REG_X0, nullptr); + + // adrp x0, #-0x4000 + check_insn_relo("\xe0\xff\xff\x90", 4, false, UC_ARM64_REG_X0, nullptr); + // adrp x0, #0x4000 + check_insn_relo("\x20\x00\x00\x90", 4, false, UC_ARM64_REG_X0, nullptr); + + // mov x0, #0 + // cmp x0, #0 + // b.eq #-0x4000 + check_insn_relo("\x00\x00\x80\xd2\x1f\x00\x00\xf1\x00\x00\xfe\x54", 12, true, -1, nullptr); + // mov x0, #0 + // cmp x0, #0 + // b.eq #0x4000 + check_insn_relo("\x00\x00\x80\xd2\x1f\x00\x00\xf1\x00\x00\x02\x54", 12, true, -1, nullptr); + + // mov x0, #0xb + // tbz w0, 2, #-0x4000 + check_insn_relo("\x60\x01\x80\xd2\x00\x00\x16\x36", 8, true, -1, nullptr); + // mov x0, #0xb + + // mov x0, #0xb + // tbz w0, 2, #0x4000 + check_insn_relo("\x60\x01\x80\xd2\x00\x00\x12\x36", 8, true, -1, nullptr); + + return 0; +} diff --git a/app/src/main/cpp/Dobby/tests/test_insn_relo_arm.cpp b/app/src/main/cpp/Dobby/tests/test_insn_relo_arm.cpp new file mode 100644 index 0000000..43dd16c --- /dev/null +++ b/app/src/main/cpp/Dobby/tests/test_insn_relo_arm.cpp @@ -0,0 +1,116 @@ +#include "InstructionRelocation/InstructionRelocation.h" + +#include "UniconEmulator.h" + +void check_insn_relo_arm(char *buffer, size_t buffer_size, bool check_fault_addr, int check_reg_id, + void (^callback)(UniconEmulator *orig, UniconEmulator *relo)) { + __attribute__((aligned(4))) char code[64] = {0}; + memcpy(code, buffer, buffer_size); + check_insn_relo(code, buffer_size, check_fault_addr, check_reg_id, callback); +} + +void check_insn_relo_thumb(char *buffer, size_t buffer_size, bool check_fault_addr, int check_reg_id, + void (^callback)(UniconEmulator *orig, UniconEmulator *relo), uintptr_t relo_stop_size = 0) { + __attribute__((aligned(4))) char code[64] = {0}; + memcpy(code, buffer, buffer_size); + check_insn_relo(code, buffer_size, check_fault_addr, check_reg_id, callback, relo_stop_size); +} + +int main() { + log_set_level(0); + set_global_arch("arm"); + + // ldr r0, [pc, #-0x20] + __attribute__((aligned(4))) char *code_0 = "\x20\x00\x1f\xe5"; + check_insn_relo(code_0, 4, true, -1, nullptr); + + // ldr r0, [pc, #0x20] + __attribute__((aligned(4))) char *code_1 = "\x20\x00\x9f\xe5"; + check_insn_relo(code_1, 4, false, -1, ^(UniconEmulator *orig, UniconEmulator *relo) { + assert(relo->getFaultAddr() == 0x10014028); + }); + + // add r0, pc, #-0x4000 + check_insn_relo_arm("\x01\x09\x4f\xe2", 4, false, UC_ARM_REG_R0, nullptr); + // add r0, pc, #0x4000 + check_insn_relo_arm("\x01\x09\x8f\xe2", 4, false, UC_ARM_REG_R0, nullptr); + + // b #-0x4000 + check_insn_relo_arm("\xfe\xef\xff\xea", 4, true, -1, nullptr); + // b #0x4000 + check_insn_relo_arm("\xfe\x0f\x00\xea", 4, true, -1, nullptr); + + // bl #-0x4000 + check_insn_relo_arm("\xfe\xef\xff\xeb", 4, true, -1, nullptr); + // blx #0x4000 + check_insn_relo_arm("\xfe\x0f\x00\xfa", 4, true, -1, nullptr); + + set_global_arch("thumb"); + + // cmp r0, pc + check_insn_relo_thumb("\x78\x45", 2, false, -1, ^(UniconEmulator *orig, UniconEmulator *relo) { + assert(relo->readRegister(UC_ARM_REG_R12) == (void *)0x10014004); + }); + + // adr r0, #0x20 + check_insn_relo_thumb("\x08\xa0", 2, false, UC_ARM_REG_R0, nullptr, 8); + + // bx pc + check_insn_relo_thumb("\x78\x47", 2, false, UC_ARM_REG_PC, nullptr); + // blx pc + check_insn_relo_thumb("\xf8\x47", 2, false, UC_ARM_REG_PC, nullptr); + + // ldr r0, [pc, #8] + check_insn_relo_thumb("\x02\x48", 2, false, -1, ^(UniconEmulator *orig, UniconEmulator *relo) { + assert(relo->getFaultAddr() == 0x1001400c); + }); + + // b #-8 + check_insn_relo_thumb("\xfa\xe7", 2, true, -1, nullptr); + // b #8 + check_insn_relo_thumb("\x02\xe0", 2, false, -1, ^(UniconEmulator *orig, UniconEmulator *relo) { + assert(relo->getFaultAddr() == 0x10014008); + }); + + // mov r0, 0 + // cbz r0, #8 + check_insn_relo_thumb("\x4f\xf0\x00\x00" + "\x10\xb1", + 6, false, -1, ^(UniconEmulator *orig, UniconEmulator *relo) { + assert(relo->getFaultAddr() == 0x1001400c); + }); + + set_global_arch("thumb"); + + // cmp r0, r0 + // beq.w #-0x4000 + check_insn_relo_thumb("\x80\x42" + "\x3c\xf4\x00\xa8", + 6, true, -1, nullptr); + // cmp r0, r0 + // beq.w #0x4000 + check_insn_relo_thumb("\x80\x42" + "\x04\xf0\x00\x80", + 6, true, -1, nullptr); + + // bl #-0x4000 + check_insn_relo_thumb("\xfb\xf7\xfe\xff", 4, true, -1, nullptr); + // blx #0x4000 + check_insn_relo_thumb("\x03\xf0\xfe\xef", 4, true, -1, nullptr); + + // adr r0, #-0x512 + check_insn_relo_thumb("\xaf\xf2\x12\x50", 4, false, UC_ARM_REG_R0, nullptr); + // adr r0, #0x512 + check_insn_relo_thumb("\x0f\xf2\x12\x50", 4, false, UC_ARM_REG_R0, nullptr); + + // ldr r0, [pc, #-0x512] + check_insn_relo_thumb("\x5f\xf8\x12\x05", 4, true, -1, nullptr, 0xc); + // ldr r0, [pc, #0x512] + check_insn_relo_thumb( + "\xdf\xf8\x12\x05", 4, false, -1, + ^(UniconEmulator *orig, UniconEmulator *relo) { + assert(relo->getFaultAddr() == 0x10014000 + 0x512 + 4); + }, + 0xc); + return 0; +} diff --git a/app/src/main/cpp/Dobby/tests/test_insn_relo_arm64.cpp b/app/src/main/cpp/Dobby/tests/test_insn_relo_arm64.cpp new file mode 100644 index 0000000..d76aee6 --- /dev/null +++ b/app/src/main/cpp/Dobby/tests/test_insn_relo_arm64.cpp @@ -0,0 +1,97 @@ +/* + +test_b: +b #-0x4000 +b #0x4000 + +test_bl: +bl #-0x4000 +bl #0x4000 + +test_cbz: +cbz x0, #-0x4000 +cbz x0, #0x4000 + +test_ldr_liberal: +ldr x0, #-0x4000 +ldr x0, #0x4000 + +test_adr: +adr x0, #-0x4000 +adr x0, #0x4000 + +test_adrp: +adrp x0, #-0x4000 +adrp x0, #0x4000 + +test_b_cond: +b.eq #-0x4000 +b.eq #0x4000 + +test_tbz: +tbz x0, #0, #-0x4000 +tbz x0, #0, #0x4000 + +*/ + +// clang -arch arm64 code_arm64.asm -o code_arm64.o + +#include "InstructionRelocation/InstructionRelocation.h" + +#include "UniconEmulator.h" + +int main() { + set_global_arch("arm64"); + + // b #-0x4000 + check_insn_relo("\x00\xf0\xff\x17", 4, true, -1, nullptr); + // b #0x4000 + check_insn_relo("\x00\x10\x00\x14", 4, true, -1, nullptr); + + // bl #-0x4000 + check_insn_relo("\x00\xf0\xff\x97", 4, true, -1, nullptr); + // bl #0x4000 + check_insn_relo("\x00\x10\x00\x94", 4, true, -1, nullptr); + + // mov x0, #0 + // cbz x0, #-0x4000 + check_insn_relo("\x00\x00\x80\xd2\x00\x00\xfe\xb4", 8, true, -1, nullptr); + // mov x0, #0 + // cbz x0, #0x4000 + check_insn_relo("\x00\x00\x80\xd2\x00\x00\x02\xb4", 8, true, -1, nullptr); + + // ldr x0, #-0x4000 + check_insn_relo("\x00\x00\xfe\x58", 4, true, -1, nullptr); + // ldr x0, #0x4000 + check_insn_relo("\x00\x00\x02\x58", 4, true, -1, nullptr); + + // adr x0, #-0x4000 + check_insn_relo("\x00\x00\xfe\x10", 4, false, UC_ARM64_REG_X0, nullptr); + // adr x0, #0x4000 + check_insn_relo("\x00\x00\x02\x10", 4, false, UC_ARM64_REG_X0, nullptr); + + // adrp x0, #-0x4000 + check_insn_relo("\xe0\xff\xff\x90", 4, false, UC_ARM64_REG_X0, nullptr); + // adrp x0, #0x4000 + check_insn_relo("\x20\x00\x00\x90", 4, false, UC_ARM64_REG_X0, nullptr); + + // mov x0, #0 + // cmp x0, #0 + // b.eq #-0x4000 + check_insn_relo("\x00\x00\x80\xd2\x1f\x00\x00\xf1\x00\x00\xfe\x54", 12, true, -1, nullptr); + // mov x0, #0 + // cmp x0, #0 + // b.eq #0x4000 + check_insn_relo("\x00\x00\x80\xd2\x1f\x00\x00\xf1\x00\x00\x02\x54", 12, true, -1, nullptr); + + // mov x0, #0xb + // tbz w0, 2, #-0x4000 + check_insn_relo("\x60\x01\x80\xd2\x00\x00\x16\x36", 8, true, -1, nullptr); + // mov x0, #0xb + + // mov x0, #0xb + // tbz w0, 2, #0x4000 + check_insn_relo("\x60\x01\x80\xd2\x00\x00\x12\x36", 8, true, -1, nullptr); + + return 0; +} diff --git a/app/src/main/cpp/Dobby/tests/test_insn_relo_x64.cpp b/app/src/main/cpp/Dobby/tests/test_insn_relo_x64.cpp new file mode 100644 index 0000000..f9db59d --- /dev/null +++ b/app/src/main/cpp/Dobby/tests/test_insn_relo_x64.cpp @@ -0,0 +1,38 @@ +#include "InstructionRelocation/InstructionRelocation.h" + +#include "UniconEmulator.h" + +int main() { + log_set_level(0); + set_global_arch("x86_64"); + + + // cmp eax, eax + // jz -0x20 + check_insn_relo("\x39\xc0\x74\xdc", 4, false, UC_X86_REG_IP, nullptr); + // cmp eax, eax + // jz 0x20 + check_insn_relo("\x39\xc0\x74\x1c", 4, false, UC_X86_REG_IP, nullptr); + + // jmp -0x20 + check_insn_relo("\xeb\xde", 2, false, UC_X86_REG_IP, nullptr); + // jmp 0x20 + check_insn_relo("\xeb\x1e", 2, false, UC_X86_REG_IP, nullptr); + + + // jmp -0x4000 + check_insn_relo("\xe9\xfb\xbf\xff\xff", 4, false, UC_X86_REG_IP, nullptr); + // jmp 0x4000 + check_insn_relo("\xe9\xfb\x3f\x00\x00", 4, false, UC_X86_REG_IP, nullptr); + + // lea rax, [rip] + check_insn_relo("\x48\x8d\x05\x00\x00\x00\x00", 7, false, UC_X86_REG_RAX, nullptr); + + // lea rax, [rip + 0x4000] + check_insn_relo("\x48\x8d\x05\x00\x40\x00\x00", 7, false, UC_X86_REG_RAX, nullptr); + + // mov rax, [rip + 0x4000] + check_insn_relo("\x48\x8b\x05\x00\x40\x00\x00", 7, true, -1, nullptr); + + return 0; +} diff --git a/app/src/main/cpp/Dobby/tests/test_native.cpp b/app/src/main/cpp/Dobby/tests/test_native.cpp new file mode 100644 index 0000000..21f84a9 --- /dev/null +++ b/app/src/main/cpp/Dobby/tests/test_native.cpp @@ -0,0 +1,30 @@ +#include "dobby.h" + +#include +#include + +#define LOG(fmt, ...) printf("[test_native] " fmt, ##__VA_ARGS__) + +void test_execve() { + char *argv[] = {NULL}; + char *envp[] = {NULL}; + + LOG("test execve"); + + DobbyInstrument(DobbySymbolResolver(0, "_execve"), [](void *, DobbyRegisterContext *ctx) { + LOG("execve: %s", (char *)ctx->general.regs.rdi); + return; + }); + + execve("ls", argv, envp); + + return; +} + +int main(int argc, char *argv[]) { + log_set_level(0); + + test_execve(); + + return 0; +} diff --git a/app/src/main/cpp/dobby/arm64-v8a/libdobby.a b/app/src/main/cpp/dobby/arm64-v8a/libdobby.a deleted file mode 100644 index e7acac6..0000000 Binary files a/app/src/main/cpp/dobby/arm64-v8a/libdobby.a and /dev/null differ diff --git a/app/src/main/cpp/dobby/armeabi-v7a/libdobby.a b/app/src/main/cpp/dobby/armeabi-v7a/libdobby.a deleted file mode 100644 index 069292c..0000000 Binary files a/app/src/main/cpp/dobby/armeabi-v7a/libdobby.a and /dev/null differ diff --git a/app/src/main/cpp/dobby/x86/libdobby.a b/app/src/main/cpp/dobby/x86/libdobby.a deleted file mode 100644 index bfe8ff9..0000000 Binary files a/app/src/main/cpp/dobby/x86/libdobby.a and /dev/null differ diff --git a/app/src/main/cpp/dobby/x86_64/libdobby.a b/app/src/main/cpp/dobby/x86_64/libdobby.a deleted file mode 100644 index ebb072f..0000000 Binary files a/app/src/main/cpp/dobby/x86_64/libdobby.a and /dev/null differ diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index e2b5dda..0352f0a 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -1,5 +1,4 @@ #include -#include #include #include "zygisk.hpp" #include "dobby.h" @@ -11,19 +10,15 @@ #define PIF_JSON "/data/adb/pif.json" -#define PIF_JSON_2 "/data/adb/modules/playintegrityfix/pif.json" - static std::string FIRST_API_LEVEL, SECURITY_PATCH, BUILD_ID; typedef void (*T_Callback)(void *, const char *, const char *, uint32_t); -static std::map callbacks; +static T_Callback o_callback = nullptr; static void modify_callback(void *cookie, const char *name, const char *value, uint32_t serial) { - if (cookie == nullptr || name == nullptr || value == nullptr || - !callbacks.contains(cookie)) - return; + if (cookie == nullptr || name == nullptr || value == nullptr || o_callback == nullptr) return; std::string_view prop(name); @@ -59,17 +54,17 @@ static void modify_callback(void *cookie, const char *name, const char *value, u LOGD("[%s] -> %s", name, value); } - return callbacks[cookie](cookie, name, value, serial); + return o_callback(cookie, name, value, serial); } -static void (*o_system_property_read_callback)(const prop_info *, T_Callback, void *); +static void (*o_system_property_read_callback)(const void *, T_Callback, void *); static void -my_system_property_read_callback(const prop_info *pi, T_Callback callback, void *cookie) { +my_system_property_read_callback(const void *pi, T_Callback callback, void *cookie) { if (pi == nullptr || callback == nullptr || cookie == nullptr) { return o_system_property_read_callback(pi, callback, cookie); } - callbacks[cookie] = callback; + o_callback = callback; return o_system_property_read_callback(pi, modify_callback, cookie); } @@ -82,8 +77,8 @@ static void doHook() { LOGD("Found '__system_property_read_callback' handle at %p", handle); DobbyHook( handle, - reinterpret_cast(my_system_property_read_callback), - reinterpret_cast(&o_system_property_read_callback) + (dobby_dummy_func_t) my_system_property_read_callback, + (dobby_dummy_func_t *) &o_system_property_read_callback ); } @@ -98,48 +93,93 @@ public: auto name = env->GetStringUTFChars(args->nice_name, nullptr); - if (name == nullptr) { - api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); - return; - } - - if (strncmp(name, "com.google.android.gms", 22) != 0) { - env->ReleaseStringUTFChars(args->nice_name, name); - api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); - return; - } - - api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT); - - if (strcmp(name, "com.google.android.gms.unstable") != 0) { - env->ReleaseStringUTFChars(args->nice_name, name); - api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); - return; - } + bool isGms = memcmp(name, "com.google.android.gms", 22) == 0; + bool isGmsUnstable = memcmp(name, "com.google.android.gms.unstable", 31) == 0; env->ReleaseStringUTFChars(args->nice_name, name); - long dexSize = 0, jsonSize = 0; + if (isGms) api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT); - int fd = api->connectCompanion(); + if (isGmsUnstable) { + long dexSize = 0, jsonSize = 0; - read(fd, &dexSize, sizeof(long)); - read(fd, &jsonSize, sizeof(long)); + int fd = api->connectCompanion(); - LOGD("Dex file size: %ld", dexSize); - LOGD("Json file size: %ld", jsonSize); + read(fd, &dexSize, sizeof(long)); + read(fd, &jsonSize, sizeof(long)); - vector.resize(dexSize); - read(fd, vector.data(), dexSize); + LOGD("Dex file size: %ld", dexSize); + LOGD("Json file size: %ld", jsonSize); - std::vector jsonVector(jsonSize); - read(fd, jsonVector.data(), jsonSize); + vector.resize(dexSize); + read(fd, vector.data(), dexSize); - close(fd); + std::vector jsonVector(jsonSize); + read(fd, jsonVector.data(), jsonSize); - std::string_view jsonStr(jsonVector.cbegin(), jsonVector.cend()); - json = nlohmann::json::parse(jsonStr, nullptr, false, true); + close(fd); + std::string_view jsonStr(jsonVector.cbegin(), jsonVector.cend()); + json = nlohmann::json::parse(jsonStr, nullptr, false, true); + + parseJson(); + + return; // We can't dlclose lib because of the hook + } + + api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); + } + + void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override { + if (vector.empty() || json.empty()) return; + + doHook(); + + injectDex(); + + vector.clear(); + json.clear(); + } + + void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override { + api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); + } + +private: + zygisk::Api *api = nullptr; + JNIEnv *env = nullptr; + std::vector vector; + nlohmann::json json; + + void injectDex() { + LOGD("get system classloader"); + auto clClass = env->FindClass("java/lang/ClassLoader"); + auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader", + "()Ljava/lang/ClassLoader;"); + auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader); + + LOGD("create class loader"); + auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader"); + auto dexClInit = env->GetMethodID(dexClClass, "", + "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); + auto buffer = env->NewDirectByteBuffer(vector.data(), vector.size()); + auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader); + + LOGD("load class"); + auto loadClass = env->GetMethodID(clClass, "loadClass", + "(Ljava/lang/String;)Ljava/lang/Class;"); + auto entryClassName = env->NewStringUTF("es.chiteroman.playintegrityfix.EntryPoint"); + auto entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName); + + auto entryClass = (jclass) entryClassObj; + + LOGD("call init"); + auto entryInit = env->GetStaticMethodID(entryClass, "init", "(Ljava/lang/String;)V"); + auto str = env->NewStringUTF(json.dump().c_str()); + env->CallStaticVoidMethod(entryClass, entryInit, str); + } + + void parseJson() { if (json.contains("FIRST_API_LEVEL")) { if (json["FIRST_API_LEVEL"].is_number_integer()) { @@ -189,51 +229,6 @@ public: LOGD("JSON file doesn't contain ID/BUILD_ID keys :("); } } - - void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override { - if (vector.empty() || json.empty()) return; - - doHook(); - - LOGD("get system classloader"); - auto clClass = env->FindClass("java/lang/ClassLoader"); - auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader", - "()Ljava/lang/ClassLoader;"); - auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader); - - LOGD("create class loader"); - auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader"); - auto dexClInit = env->GetMethodID(dexClClass, "", - "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); - auto buffer = env->NewDirectByteBuffer(vector.data(), vector.size()); - auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader); - - LOGD("load class"); - auto loadClass = env->GetMethodID(clClass, "loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;"); - auto entryClassName = env->NewStringUTF("es.chiteroman.playintegrityfix.EntryPoint"); - auto entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName); - - auto entryClass = (jclass) entryClassObj; - - LOGD("call init"); - auto entryInit = env->GetStaticMethodID(entryClass, "init", "(Ljava/lang/String;)V"); - auto str = env->NewStringUTF(json.dump().c_str()); - env->CallStaticVoidMethod(entryClass, entryInit, str); - - vector.clear(); - json.clear(); - } - - void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override { - api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); - } - -private: - zygisk::Api *api = nullptr; - JNIEnv *env = nullptr; - std::vector vector; - nlohmann::json json; }; static void companion(int fd) { @@ -254,8 +249,7 @@ static void companion(int fd) { fclose(dexFile); } - FILE *jsonFile = fopen(PIF_JSON, "rb"); - if (jsonFile == nullptr) jsonFile = fopen(PIF_JSON_2, "rb"); + FILE *jsonFile = fopen(PIF_JSON, "r"); if (jsonFile) { diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/CustomKeyStoreSpi.java b/app/src/main/java/es/chiteroman/playintegrityfix/CustomKeyStoreSpi.java deleted file mode 100644 index 72ec9a3..0000000 --- a/app/src/main/java/es/chiteroman/playintegrityfix/CustomKeyStoreSpi.java +++ /dev/null @@ -1,105 +0,0 @@ -package es.chiteroman.playintegrityfix; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.Key; -import java.security.KeyStoreException; -import java.security.KeyStoreSpi; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.util.Date; -import java.util.Enumeration; -import java.util.Locale; - -public final class CustomKeyStoreSpi extends KeyStoreSpi { - public static volatile KeyStoreSpi keyStoreSpi; - - @Override - public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException { - return keyStoreSpi.engineGetKey(alias, password); - } - - @Override - public Certificate[] engineGetCertificateChain(String alias) { - for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) { - if (stackTraceElement.getClassName().toLowerCase(Locale.US).contains("droidguard")) { - EntryPoint.LOG("DroidGuard call certificate chain! Throw exception."); - throw new UnsupportedOperationException(); - } - } - return keyStoreSpi.engineGetCertificateChain(alias); - } - - @Override - public Certificate engineGetCertificate(String alias) { - return keyStoreSpi.engineGetCertificate(alias); - } - - @Override - public Date engineGetCreationDate(String alias) { - return keyStoreSpi.engineGetCreationDate(alias); - } - - @Override - public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException { - keyStoreSpi.engineSetKeyEntry(alias, key, password, chain); - } - - @Override - public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException { - keyStoreSpi.engineSetKeyEntry(alias, key, chain); - } - - @Override - public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException { - keyStoreSpi.engineSetCertificateEntry(alias, cert); - } - - @Override - public void engineDeleteEntry(String alias) throws KeyStoreException { - keyStoreSpi.engineDeleteEntry(alias); - } - - @Override - public Enumeration engineAliases() { - return keyStoreSpi.engineAliases(); - } - - @Override - public boolean engineContainsAlias(String alias) { - return keyStoreSpi.engineContainsAlias(alias); - } - - @Override - public int engineSize() { - return keyStoreSpi.engineSize(); - } - - @Override - public boolean engineIsKeyEntry(String alias) { - return keyStoreSpi.engineIsKeyEntry(alias); - } - - @Override - public boolean engineIsCertificateEntry(String alias) { - return keyStoreSpi.engineIsCertificateEntry(alias); - } - - @Override - public String engineGetCertificateAlias(Certificate cert) { - return keyStoreSpi.engineGetCertificateAlias(cert); - } - - @Override - public void engineStore(OutputStream stream, char[] password) throws CertificateException, IOException, NoSuchAlgorithmException { - keyStoreSpi.engineStore(stream, password); - } - - @Override - public void engineLoad(InputStream stream, char[] password) throws CertificateException, IOException, NoSuchAlgorithmException { - keyStoreSpi.engineLoad(stream, password); - } -} diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java b/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java index 3ec3fb4..0382e3e 100644 --- a/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java +++ b/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java @@ -1,6 +1,7 @@ package es.chiteroman.playintegrityfix; import java.security.Provider; +import java.security.ProviderException; public final class CustomProvider extends Provider { @@ -8,15 +9,16 @@ public final class CustomProvider extends Provider { super(provider.getName(), provider.getVersion(), provider.getInfo()); putAll(provider); - - put("KeyStore.AndroidKeyStore", CustomKeyStoreSpi.class.getName()); } @Override public synchronized Service getService(String type, String algorithm) { EntryPoint.LOG(String.format("[Service] Type: '%s' | Algorithm: '%s'", type, algorithm)); - if ("KeyStore".equals(type)) EntryPoint.spoofDevice(); + if ("AndroidKeyStore".equals(algorithm)) { + EntryPoint.spoofFields(); + throw new ProviderException(); + } return super.getService(type, algorithm); } diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java index d3acf00..404fbd6 100644 --- a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java +++ b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java @@ -7,8 +7,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.lang.reflect.Field; -import java.security.KeyStore; -import java.security.KeyStoreSpi; import java.security.Provider; import java.security.Security; @@ -16,22 +14,6 @@ public final class EntryPoint { private static JSONObject jsonObject = new JSONObject(); static { - try { - spoofProvider(); - } catch (Throwable t) { - LOG("spoofProvider exception: " + t); - } - } - - private static void spoofProvider() throws Exception { - KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); - keyStore.load(null); - - Field f = keyStore.getClass().getDeclaredField("keyStoreSpi"); - f.setAccessible(true); - CustomKeyStoreSpi.keyStoreSpi = (KeyStoreSpi) f.get(keyStore); - f.setAccessible(false); - Provider provider = Security.getProvider("AndroidKeyStore"); Provider customProvider = new CustomProvider(provider); @@ -39,23 +21,20 @@ public final class EntryPoint { Security.removeProvider("AndroidKeyStore"); Security.insertProviderAt(customProvider, 1); - LOG("Spoof KeyStoreSpi and Provider done!"); + LOG("Spoof Provider done!"); } public static void init(String json) { + try { jsonObject = new JSONObject(json); - spoofDevice(); + spoofFields(); } catch (JSONException e) { LOG("Couldn't parse JSON from Zygisk"); } } - static void LOG(String msg) { - Log.d("PIF/Java", msg); - } - - static void spoofDevice() { + public static void spoofFields() { jsonObject.keys().forEachRemaining(s -> { try { Object value = jsonObject.get(s); @@ -104,4 +83,8 @@ public final class EntryPoint { return field; } + + public static void LOG(String msg) { + Log.d("PIF/Java", msg); + } } diff --git a/changelog.md b/changelog.md index 072f65b..1f79d85 100644 --- a/changelog.md +++ b/changelog.md @@ -1,12 +1,7 @@ -We have a Telegram channel! +We have a Telegram group! If you want to share your knowledge join: https://t.me/playintegrityfix -# v15.1 +# v15.2 -Emergency update 🚨 - -- Fix few bugs. -- Using v14.6 fingerprint, so you can pass DEVICE. - -MODULE WON'T PROVIDE MORE FINGERPRINTS WHEN GOOGLE BAN THIS ONE. \ No newline at end of file +Fingerprint is not included. \ No newline at end of file diff --git a/module/customize.sh b/module/customize.sh index 8be9094..babb43a 100644 --- a/module/customize.sh +++ b/module/customize.sh @@ -50,9 +50,4 @@ if [ -d "/system/app/EliteDevelopmentModule" ]; then touch "$directory/.replace" ui_print "- EliteDevelopmentModule app removed." -fi - -if [ -f "/data/adb/pif.json" ]; then - mv -f "/data/adb/pif.json" "/data/adb/pif.json.old" - ui_print "- Backup pif.json" fi \ No newline at end of file diff --git a/module/pif.json b/module/pif.json deleted file mode 100644 index fba7312..0000000 --- a/module/pif.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "PRODUCT": "c01_ww", - "DEVICE": "acer_c01", - "MANUFACTURER": "Acer Inc.", - "BRAND": "acer", - "MODEL": "C01", - "FINGERPRINT": "acer/c01_ww/acer_c01:7.1.1/NMF26F/1521514970:user/release-keys", - "SECURITY_PATCH": "2018-04-01", - "FIRST_API_LEVEL": 24, - "ID": "NMF26F" -} \ No newline at end of file diff --git a/update.json b/update.json index 938f4af..d545798 100644 --- a/update.json +++ b/update.json @@ -1,6 +1,6 @@ { - "version": "v15.1", - "versionCode": 15100, - "zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v15.1/PlayIntegrityFix.zip", + "version": "v15.2", + "versionCode": 15200, + "zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v15.2/PlayIntegrityFix_v15.2.zip", "changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md" } \ No newline at end of file