mirror of
https://github.com/chiteroman/PlayIntegrityFix.git
synced 2025-01-18 19:12:38 +02:00
Prepare v15.7
This commit is contained in:
parent
92eee68b67
commit
bdef42962f
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/libcxx" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -12,8 +12,8 @@ android {
|
||||
applicationId = "es.chiteroman.playintegrityfix"
|
||||
minSdk = 26
|
||||
targetSdk = 34
|
||||
versionCode = 15600
|
||||
versionName = "v15.6"
|
||||
versionCode = 15700
|
||||
versionName = "v15.7"
|
||||
multiDexEnabled = false
|
||||
|
||||
buildFeatures {
|
||||
@ -24,16 +24,20 @@ android {
|
||||
jniLibs {
|
||||
excludes += "**/liblog.so"
|
||||
excludes += "**/libdobby.so"
|
||||
excludes += "**/libshadowhook.so"
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndk {
|
||||
abiFilters += "arm64-v8a"
|
||||
abiFilters += "armeabi-v7a"
|
||||
cmake {
|
||||
arguments += "-DANDROID_STL=none"
|
||||
arguments += "-DCMAKE_BUILD_TYPE=MinSizeRel"
|
||||
arguments += "-DPlugin.Android.BionicLinkerUtil=ON"
|
||||
|
||||
jobs = Runtime.getRuntime().availableProcessors()
|
||||
cppFlags += "-std=c++20"
|
||||
cppFlags += "-fno-exceptions"
|
||||
cppFlags += "-fno-rtti"
|
||||
cppFlags += "-fvisibility=hidden"
|
||||
cppFlags += "-fvisibility-inlines-hidden"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -53,12 +57,17 @@ android {
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path = file("src/main/cpp/Android.mk")
|
||||
cmake {
|
||||
path = file("src/main/cpp/CMakeLists.txt")
|
||||
version = "3.22.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0")
|
||||
}
|
||||
|
||||
tasks.register("updateModuleProp") {
|
||||
doLast {
|
||||
val versionName = project.android.defaultConfig.versionName
|
||||
|
@ -1,30 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := playintegrityfix
|
||||
LOCAL_SRC_FILES := $(LOCAL_PATH)/main.cpp
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/cJSON/cJSON.c)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/*.c)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/common/*.c)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/third_party/xdl/*.c)
|
||||
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/cJSON
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/common
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/bsd
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/lss
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/xdl
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/arch/arm/*.c)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/arch/arm
|
||||
else ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
||||
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/arch/arm64/*.c)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/arch/arm64
|
||||
endif
|
||||
|
||||
LOCAL_LDLIBS := -llog
|
||||
include $(BUILD_SHARED_LIBRARY)
|
@ -1,8 +0,0 @@
|
||||
APP_STL := system
|
||||
APP_ABI := armeabi-v7a arm64-v8a
|
||||
APP_CFLAGS := -Oz -flto -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -fno-threadsafe-statics -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector
|
||||
APP_CPPFLAGS := -std=c++2b -fno-exceptions -fno-rtti
|
||||
APP_CONLYFLAGS := -std=c2x
|
||||
APP_LDFLAGS := -Oz -flto -Wl,--exclude-libs,ALL -Wl,--gc-sections
|
||||
APP_PLATFORM := android-26
|
||||
APP_THIN_ARCHIVE := true
|
13
app/src/main/cpp/CMakeLists.txt
Normal file
13
app/src/main/cpp/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
project(playintegrityfix)
|
||||
|
||||
find_package(cxx REQUIRED CONFIG)
|
||||
|
||||
link_libraries(cxx::cxx)
|
||||
|
||||
add_library(${CMAKE_PROJECT_NAME} SHARED main.cpp)
|
||||
|
||||
add_subdirectory(Dobby)
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC log dobby_static)
|
18
app/src/main/cpp/Dobby/.clang-format
Normal file
18
app/src/main/cpp/Dobby/.clang-format
Normal file
@ -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
|
80
app/src/main/cpp/Dobby/.gitignore
vendored
Normal file
80
app/src/main/cpp/Dobby/.gitignore
vendored
Normal file
@ -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
|
384
app/src/main/cpp/Dobby/CMakeLists.txt
Normal file
384
app/src/main/cpp/Dobby/CMakeLists.txt
Normal file
@ -0,0 +1,384 @@
|
||||
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)$")
|
||||
|
||||
# --- options
|
||||
|
||||
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(DOBBY_BUILD_EXAMPLE "Build example" OFF)
|
||||
|
||||
option(DOBBY_BUILD_TEST "Build test" OFF)
|
||||
|
||||
# --- private
|
||||
option(DOBBY_BUILD_KERNEL_MODE "Build xnu kernel mode" OFF)
|
||||
|
||||
option(Private.Obfuscation "Enable llvm obfuscation" OFF)
|
||||
|
||||
if ((NOT DEFINED CMAKE_BUILD_TYPE) OR (CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
set(DOBBY_DEBUG ON)
|
||||
endif ()
|
||||
|
||||
|
||||
set(compile_definitions "")
|
||||
|
||||
# for arm64, allow access q8 - q31
|
||||
if (FullFloatingPointRegisterPack)
|
||||
set(compile_definitions "${compile_definitions} -DFULL_FLOATING_POINT_REGISTER_PACK")
|
||||
endif ()
|
||||
|
||||
if (DOBBY_BUILD_KERNEL_MODE)
|
||||
set(compile_definitions "${compile_definitions} -DBUILDING_KERNEL")
|
||||
endif ()
|
||||
|
||||
if (DOBBY_DEBUG)
|
||||
set(compile_definitions "${compile_definitions} -DDOBBY_DEBUG")
|
||||
else ()
|
||||
set(compile_definitions "${compile_definitions} -DDOBBY_LOGGING_DISABLE")
|
||||
endif ()
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL Xcode)
|
||||
endif ()
|
||||
|
||||
include(cmake/compiler_and_linker.cmake)
|
||||
|
||||
message(STATUS "[Dobby] CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS "[Dobby] DOBBY_DEBUG: ${DOBBY_DEBUG}")
|
||||
message(STATUS "[Dobby] NearBranch: ${NearBranch}")
|
||||
message(STATUS "[Dobby] FullFloatingPointRegisterPack: ${FullFloatingPointRegisterPack}")
|
||||
message(STATUS "[Dobby] Plugin.SymbolResolver: ${Plugin.SymbolResolver}")
|
||||
message(STATUS "[Dobby] Plugin.ImportTableReplace: ${Plugin.ImportTableReplace}")
|
||||
message(STATUS "[Dobby] Plugin.Android.BionicLinkerUtil: ${Plugin.Android.BionicLinkerUtil}")
|
||||
message(STATUS "[Dobby] DOBBY_BUILD_EXAMPLE: ${DOBBY_BUILD_EXAMPLE}")
|
||||
message(STATUS "[Dobby] DOBBY_BUILD_TEST: ${DOBBY_BUILD_TEST}")
|
||||
message(STATUS "[Dobby] DOBBY_BUILD_KERNEL_MODE: ${DOBBY_BUILD_KERNEL_MODE}")
|
||||
message(STATUS "[Dobby] Private.Obfuscation: ${Private.Obfuscation}")
|
||||
|
||||
# ---
|
||||
|
||||
include_directories(
|
||||
.
|
||||
./include
|
||||
./source
|
||||
source/dobby
|
||||
|
||||
./external
|
||||
./external/logging
|
||||
|
||||
./builtin-plugin
|
||||
)
|
||||
|
||||
if (SYSTEM.Darwin AND (NOT DOBBY_BUILD_KERNEL_MODE))
|
||||
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 NOT DOBBY_BUILD_KERNEL_MODE)
|
||||
set(dobby.SOURCE_FILE_LIST ${dobby.SOURCE_FILE_LIST}
|
||||
source/Backend/UserMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc
|
||||
|
||||
source/Backend/UserMode/UnifiedInterface/platform-posix.cc
|
||||
|
||||
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}
|
||||
source/Backend/UserMode/PlatformUtil/Linux/ProcessRuntimeUtility.cc
|
||||
|
||||
source/Backend/UserMode/UnifiedInterface/platform-posix.cc
|
||||
|
||||
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}
|
||||
source/Backend/UserMode/PlatformUtil/Windows/ProcessRuntimeUtility.cc
|
||||
|
||||
source/Backend/UserMode/UnifiedInterface/platform-windows.cc
|
||||
|
||||
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 DOBBY_BUILD_KERNEL_MODE))
|
||||
include_directories(
|
||||
source/Backend/UserMode/ExecMemory/substrated
|
||||
)
|
||||
set(compile_definitions "${compile_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)
|
||||
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)
|
||||
|
||||
# add osbase library
|
||||
add_subdirectory(external/osbase)
|
||||
|
||||
# ---
|
||||
|
||||
if (Plugin.SymbolResolver)
|
||||
include_directories(builtin-plugin/SymbolResolver)
|
||||
add_subdirectory(builtin-plugin/SymbolResolver)
|
||||
get_target_property(symbol_resolver.SOURCE_FILE_LIST dobby_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
|
||||
string(TIMESTAMP TODAY "%Y%m%d")
|
||||
set(VERSION_REVISION "-${TODAY}")
|
||||
if (EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
execute_process(
|
||||
COMMAND git rev-parse --short --verify HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE VERSION_COMMIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if (VERSION_COMMIT_HASH)
|
||||
set(VERSION_REVISION "${VERSION_REVISION}-${VERSION_COMMIT_HASH}")
|
||||
endif ()
|
||||
endif ()
|
||||
set(DOBBY_BUILD_VERSION "Dobby${VERSION_REVISION}")
|
||||
set(compile_definitions "${compile_definitions} -D__DOBBY_BUILD_VERSION__=\"${DOBBY_BUILD_VERSION}\"")
|
||||
message(STATUS "[Dobby] ${DOBBY_BUILD_VERSION}")
|
||||
|
||||
# ---
|
||||
|
||||
set(SOURCE_FILE_LIST
|
||||
${dobby.HEADER_FILE_LIST}
|
||||
${dobby.SOURCE_FILE_LIST}
|
||||
${logging.SOURCE_FILE_LIST}
|
||||
${dobby.plugin.SOURCE_FILE_LIST}
|
||||
)
|
||||
|
||||
get_absolute_path_list(SOURCE_FILE_LIST SOURCE_FILE_LIST_)
|
||||
set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST_})
|
||||
|
||||
add_library(dobby SHARED
|
||||
${SOURCE_FILE_LIST}
|
||||
)
|
||||
|
||||
target_include_directories(dobby PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
# ---
|
||||
|
||||
add_library(dobby_static STATIC
|
||||
${SOURCE_FILE_LIST}
|
||||
)
|
||||
|
||||
target_include_directories(dobby_static PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
set_target_properties(dobby_static
|
||||
PROPERTIES OUTPUT_NAME "dobby"
|
||||
)
|
||||
|
||||
# ---
|
||||
|
||||
set_target_properties(dobby
|
||||
PROPERTIES
|
||||
LINK_FLAGS "${linker_flags}"
|
||||
COMPILE_FLAGS "${compiler_flags}"
|
||||
)
|
||||
|
||||
set_target_properties(dobby_static
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${compiler_flags}"
|
||||
)
|
||||
|
||||
target_compile_definitions(dobby PRIVATE
|
||||
"COMPILE_DEFINITIONS ${compile_definitions}"
|
||||
)
|
||||
target_compile_definitions(dobby_static PRIVATE
|
||||
"COMPILE_DEFINITIONS ${compile_definitions}"
|
||||
)
|
||||
|
||||
# ---
|
||||
|
||||
if (Private.Obfuscation)
|
||||
set(linker_flags "${linker_flags} -Wl,-mllvm -Wl,-obfuscator-conf=all")
|
||||
endif ()
|
||||
|
||||
# ---
|
||||
|
||||
if (SYSTEM.Android)
|
||||
target_link_libraries(dobby log)
|
||||
if (PROCESSOR.ARM)
|
||||
set_target_properties(dobby
|
||||
PROPERTIES
|
||||
ANDROID_ARM_MODE arm
|
||||
)
|
||||
set_target_properties(dobby_static
|
||||
PROPERTIES
|
||||
ANDROID_ARM_MODE arm
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (SYSTEM.Linux)
|
||||
target_link_libraries(dobby dl)
|
||||
endif ()
|
||||
|
||||
# ---
|
||||
|
||||
if (DOBBY_BUILD_EXAMPLE AND (NOT DOBBY_BUILD_KERNEL_MODE))
|
||||
add_subdirectory(examples)
|
||||
endif ()
|
||||
|
||||
if (DOBBY_BUILD_TEST AND (NOT DOBBY_BUILD_KERNEL_MODE))
|
||||
add_subdirectory(tests)
|
||||
endif ()
|
||||
|
||||
# ---
|
||||
|
||||
if (SYSTEM.Darwin AND (NOT DOBBY_BUILD_KERNEL_MODE))
|
||||
include(cmake/platform/platform-darwin.cmake)
|
||||
endif ()
|
201
app/src/main/cpp/Dobby/LICENSE
Normal file
201
app/src/main/cpp/Dobby/LICENSE
Normal file
@ -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.
|
26
app/src/main/cpp/Dobby/README.md
Normal file
26
app/src/main/cpp/Dobby/README.md
Normal file
@ -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)
|
3
app/src/main/cpp/Dobby/README_zh-cn.md
Normal file
3
app/src/main/cpp/Dobby/README_zh-cn.md
Normal file
@ -0,0 +1,3 @@
|
||||
## Dobby
|
||||
|
||||
**待更新**
|
@ -0,0 +1,46 @@
|
||||
#include "./dobby_monitor.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#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
|
@ -0,0 +1,94 @@
|
||||
#include <stdlib.h> /* getenv */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "dobby.h"
|
||||
|
||||
#include "dobby/common.h"
|
||||
|
||||
#define LOG_TAG "DynamicLoaderMonitor"
|
||||
|
||||
std::unordered_map<void *, const char *> 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);
|
||||
INFO_LOG("[-] 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);
|
||||
INFO_LOG("[-] 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<void *, const char *>::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) {
|
||||
INFO_LOG("[-] 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) {
|
||||
INFO_LOG("[-] 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
|
@ -0,0 +1,97 @@
|
||||
#include <stdlib.h> /* getenv */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "./dobby_monitor.h"
|
||||
|
||||
std::unordered_map<FILE *, const char *> *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<FILE *, const char *>::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<FILE *, const char *>();
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#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;
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
#include "./dobby_monitor.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
#include <stdlib.h> /* getenv */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "dobby.h"
|
||||
#include "dobby/common.h"
|
||||
|
||||
#define LOG_TAG "PosixFileOperationMonitor"
|
||||
|
||||
std::unordered_map<int, const char *> *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);
|
||||
INFO_LOG("[-] trace open handle: %s", pathname);
|
||||
|
||||
if (posix_file_descriptors == NULL) {
|
||||
posix_file_descriptors = new std::unordered_map<int, const char *>();
|
||||
}
|
||||
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);
|
||||
INFO_LOG("[-] 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<int, const char *>();
|
||||
}
|
||||
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<int, const char *>::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) {
|
||||
INFO_LOG("[-] 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) {
|
||||
INFO_LOG("[-] 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) {
|
||||
INFO_LOG("[-] 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
|
@ -0,0 +1,57 @@
|
||||
#include <stdlib.h> /* getenv */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
std::unordered_map<int, const char *> 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<int, const char *>::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) {
|
||||
INFO_LOG("[-] 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) {
|
||||
INFO_LOG("[-] 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) {
|
||||
INFO_LOG("[-] recv: %s, buf: %p, len: %zu\n", traced_socket, buf, len);
|
||||
}
|
||||
return orig_recv(sockfd, buf, len, flags);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
#include "dobby.h"
|
||||
|
||||
#include "bionic_linker_util.h"
|
||||
|
||||
#include "logging/logging.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#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");
|
||||
INFO_LOG("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
|
||||
INFO_LOG("vm %p", vm);
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
#include "bionic_linker_util.h"
|
||||
|
||||
#include <elf.h>
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include "dobby.h"
|
||||
#include "dobby_symbol_resolver.h"
|
||||
|
||||
#include "dobby/common.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 <sys/system_properties.h>
|
||||
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<soinfo_t> linker_solist;
|
||||
std::vector<soinfo_t> 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);
|
||||
INFO_LOG("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<std::string> 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<std::string> orig_ld_library_paths =
|
||||
*(std::vector<std::string> *)((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<std::string> paths(orig_ld_library_paths.begin(), orig_ld_library_paths.end());
|
||||
orig_ld_library_paths.assign(paths.begin(), paths.end());
|
||||
}
|
||||
} else {
|
||||
*(std::vector<std::string> *)((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) {
|
||||
INFO_LOG("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);
|
||||
|
||||
INFO_LOG("disable namespace restriction done");
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
15
app/src/main/cpp/Dobby/builtin-plugin/CMakeLists.txt
Normal file
15
app/src/main/cpp/Dobby/builtin-plugin/CMakeLists.txt
Normal file
@ -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 ()
|
@ -0,0 +1,3 @@
|
||||
add_library(dobby_import_replace INTERFACE
|
||||
dobby_import_replace.cc
|
||||
)
|
@ -0,0 +1,192 @@
|
||||
#include "dobby_import_replace.h"
|
||||
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "dobby/common.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<RuntimeModule> 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
|
||||
INFO_LOG("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;
|
||||
}
|
@ -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
|
@ -0,0 +1,7 @@
|
||||
add_library(objc_runtime_replace
|
||||
dobby_objc_runtime_replace.mm
|
||||
)
|
||||
|
||||
target_link_libraries(objc_runtime_replace
|
||||
"-framework Foundation"
|
||||
)
|
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
#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
|
@ -0,0 +1,54 @@
|
||||
#include "dobby_objc_runtime_repalce.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
/* 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_) {
|
||||
// DEBUG_LOG("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_) {
|
||||
// ERROR_LOG("Not found class: %s, selector: %s method\n", class_name, selector_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto 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_) {
|
||||
// DEBUG_LOG("Not found class: %s, selector: %s method\n", class_name, selector_name);
|
||||
return NULL;
|
||||
}
|
||||
return (void *)method_getImplementation(method_);
|
||||
}
|
@ -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(
|
||||
.
|
||||
)
|
||||
|
@ -0,0 +1 @@
|
||||
Monitor all supervisor call
|
@ -0,0 +1,193 @@
|
||||
#include "dobby/dobby_internal.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <mach/mach.h>
|
||||
|
||||
#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);
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
#include "misc_utility.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uintptr_t addr_t;
|
||||
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.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
|
||||
|
||||
// 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);
|
@ -0,0 +1,95 @@
|
||||
#include "dobby/dobby_internal.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <mach/mach.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#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;
|
||||
// INFO_LOG("syscall svc ptrace deny");
|
||||
}
|
||||
}
|
||||
if (syscall_rum == SYS_exit) {
|
||||
// INFO_LOG("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;
|
||||
// INFO_LOG("svc ptrace deny");
|
||||
}
|
||||
}
|
||||
if (syscall_rum == SYS_exit) {
|
||||
// INFO_LOG("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 <sys/sysctl.h>
|
||||
__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) {
|
||||
INFO_LOG("not found func %s", sensitive_func_array[i]);
|
||||
continue;
|
||||
}
|
||||
int func_svc_offset = get_func_svc_offset(func_addr);
|
||||
if (func_svc_offset == 0) {
|
||||
INFO_LOG("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);
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
#include "SupervisorCallMonitor/misc_utility.h"
|
||||
#include "dobby/dobby_internal.h"
|
||||
#include "PlatformUtil/ProcessRuntimeUtility.h"
|
||||
|
||||
#include "misc-helper/async_logger.h"
|
||||
|
||||
#include <vector>
|
||||
std::vector<DBICallTy> *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<DBICallTy>();
|
||||
}
|
||||
g_supervisor_call_handlers->push_back(handler);
|
||||
}
|
||||
|
||||
std::vector<addr_t> *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<addr_t>();
|
||||
}
|
||||
|
||||
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)) {
|
||||
INFO_LOG("[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");
|
||||
INFO_LOG("HOME: %s", logger_path);
|
||||
async_logger_init(logger_path);
|
||||
|
||||
dobby_enable_near_branch_trampoline();
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
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();
|
@ -0,0 +1,98 @@
|
||||
#include "dobby/dobby_internal.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#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);
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
|
||||
#include "dobby/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
|
@ -0,0 +1,55 @@
|
||||
set(SOURCE_FILE_LIST)
|
||||
|
||||
include_directories(
|
||||
.
|
||||
)
|
||||
|
||||
if (NOT DEFINED DOBBY_DIR)
|
||||
message(FATAL_ERROR "DOBBY_DIR must be set!")
|
||||
endif ()
|
||||
|
||||
if (SYSTEM.Darwin)
|
||||
add_library(macho_ctx_kit
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/macho/macho_ctx.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/macho/macho_ctx.cc
|
||||
)
|
||||
|
||||
add_library(shared_cache_ctx_kit
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/macho/shared_cache_ctx.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/macho/shared_cache_ctx.cpp
|
||||
)
|
||||
|
||||
set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST}
|
||||
macho/macho_ctx.cc
|
||||
macho/dobby_symbol_resolver.cc
|
||||
)
|
||||
|
||||
if (NOT DOBBY_BUILD_KERNEL_MODE)
|
||||
set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST}
|
||||
macho/macho_file_symbol_resolver.cpp
|
||||
macho/shared_cache_ctx.cpp
|
||||
${DOBBY_DIR}/source/Backend/UserMode/PlatformUtil/Darwin/ProcessRuntimeUtility.cc
|
||||
)
|
||||
endif ()
|
||||
elseif (SYSTEM.Linux OR SYSTEM.Android)
|
||||
set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST}
|
||||
elf/dobby_symbol_resolver.cc
|
||||
|
||||
${DOBBY_DIR}/source/Backend/UserMode/PlatformUtil/Linux/ProcessRuntimeUtility.cc
|
||||
)
|
||||
elseif (SYSTEM.Windows)
|
||||
set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST}
|
||||
pe/dobby_symbol_resolver.cc
|
||||
|
||||
${DOBBY_DIR}/source/Backend/UserMode/PlatformUtil/Windows/ProcessRuntimeUtility.cc
|
||||
)
|
||||
endif ()
|
||||
|
||||
get_absolute_path_list(SOURCE_FILE_LIST SOURCE_FILE_LIST_)
|
||||
set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST_})
|
||||
|
||||
add_library(dobby_symbol_resolver
|
||||
${SOURCE_FILE_LIST}
|
||||
)
|
||||
|
||||
|
@ -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
|
@ -0,0 +1,238 @@
|
||||
#include "SymbolResolver/dobby_symbol_resolver.h"
|
||||
#include "dobby/common.h"
|
||||
|
||||
#include <elf.h>
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mmap_file_util.h"
|
||||
|
||||
#include "PlatformUtil/ProcessRuntimeUtility.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG "DobbySymbolResolver"
|
||||
|
||||
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<ElfW(Phdr) *>(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<ElfW(Dyn) *>(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<const char *>(addr + d->d_un.d_ptr);
|
||||
} else if (d->d_tag == DT_SYMTAB) {
|
||||
symtab = reinterpret_cast<ElfW(Sym) *>(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<ElfW(Shdr) *>(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);
|
||||
|
||||
if (module.load_address) {
|
||||
auto mmapFileMng = MmapFileManager(module.path);
|
||||
auto file_mem = mmapFileMng.map();
|
||||
|
||||
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 (!result) {
|
||||
auto ProcessModuleMap = ProcessRuntimeUtility::GetProcessModuleMap();
|
||||
for (auto module : ProcessModuleMap) {
|
||||
|
||||
if (module.load_address) {
|
||||
auto mmapFileMng = MmapFileManager(module.path);
|
||||
auto file_mem = mmapFileMng.map();
|
||||
|
||||
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 (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// impl at "android_restriction.cc"
|
||||
extern std::vector<void *> 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;
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
#include "dobby_symbol_resolver.h"
|
||||
#include "macho/dobby_symbol_resolver_priv.h"
|
||||
#include "macho_file_symbol_resolver.h"
|
||||
|
||||
#include "dobby/common.h"
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
|
||||
#include "PlatformUtil/ProcessRuntimeUtility.h"
|
||||
|
||||
#include "macho_ctx.h"
|
||||
#include "shared_cache_ctx.h"
|
||||
|
||||
#if !defined(BUILDING_KERNEL)
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
#endif
|
||||
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG "DobbySymbolResolver"
|
||||
|
||||
PUBLIC void *DobbySymbolResolver(const char *image_name, const char *symbol_name_pattern) {
|
||||
uintptr_t result = 0;
|
||||
auto modules = ProcessRuntimeUtility::GetProcessModuleMap();
|
||||
|
||||
for (auto iter = modules.begin(); iter != modules.end(); iter++) {
|
||||
auto module = *iter;
|
||||
|
||||
// image filter
|
||||
if (image_name && !strstr(module.path, image_name))
|
||||
continue;
|
||||
|
||||
// dyld in shared cached at new os version
|
||||
// ignore dyld, as some functions as own implementation in dyld
|
||||
if (!image_name && strstr(module.path, "dyld"))
|
||||
continue;
|
||||
|
||||
auto header = (mach_header_t *)module.load_address;
|
||||
if (header == nullptr)
|
||||
continue;
|
||||
|
||||
#if 0
|
||||
DEBUG_LOG("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;
|
||||
shared_cache_ctx_init(&shared_cache_ctx);
|
||||
shared_cache_load_symbols(&shared_cache_ctx);
|
||||
}
|
||||
if (shared_cache_ctx.mmap_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 = macho_iterate_symbol_table((char *)symbol_name_pattern, symtab, symtab_count, strtab);
|
||||
}
|
||||
if (result) {
|
||||
result = result + shared_cache_ctx.runtime_slide;
|
||||
return (void *)result;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
macho_ctx_t macho_ctx(header);
|
||||
result = macho_ctx.symbol_resolve(symbol_name_pattern);
|
||||
if (result) {
|
||||
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(dyld_header);
|
||||
result = dyld_ctx.symbol_resolve(symbol_name_pattern);
|
||||
|
||||
bool is_dyld_in_cache = ((mach_header_t *)dyld_header)->flags & MH_DYLIB_IN_CACHE;
|
||||
if (!is_dyld_in_cache && result == 0) {
|
||||
result = macho_file_symbol_resolve(dyld_header->cputype, dyld_header->cpusubtype, "/usr/lib/dyld",
|
||||
(char *)symbol_name_pattern);
|
||||
result += (uintptr_t)dyld_header;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (result == 0) {
|
||||
DEBUG_LOG("symbol resolver failed: %s", symbol_name_pattern);
|
||||
}
|
||||
|
||||
return (void *)result;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#include <stdint.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
|
||||
#include "macho_ctx.h"
|
||||
|
@ -0,0 +1,358 @@
|
||||
#include "macho_ctx.h"
|
||||
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ASSERT(x)
|
||||
|
||||
uintptr_t macho_iterate_symbol_table(char *symbol_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
|
||||
printf("> %s", symbol_name);
|
||||
#endif
|
||||
if (strcmp(symbol_name_pattern, symbol_name) == 0) {
|
||||
return symtab[i].n_value;
|
||||
}
|
||||
if (symbol_name[0] == '_') {
|
||||
if (strcmp(symbol_name_pattern, &symbol_name[1]) == 0) {
|
||||
return symtab[i].n_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
void macho_ctx_t::init(mach_header_t *header, bool is_runtime_mode) {
|
||||
memset(this, 0, sizeof(macho_ctx_t));
|
||||
|
||||
this->is_runtime_mode = is_runtime_mode;
|
||||
|
||||
this->header = header;
|
||||
segment_command_t *curr_seg_cmd;
|
||||
segment_command_t *text_segment = 0, *text_exec_segment = 0, *data_segment = 0, *data_const_segment = 0,
|
||||
*linkedit_segment = 0;
|
||||
struct symtab_command *symtab_cmd = 0;
|
||||
struct dysymtab_command *dysymtab_cmd = 0;
|
||||
struct dyld_info_command *dyld_info_cmd = 0;
|
||||
struct linkedit_data_command *exports_trie_cmd = 0;
|
||||
struct linkedit_data_command *chained_fixups_cmd = NULL;
|
||||
|
||||
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
|
||||
this->segments[this->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;
|
||||
} else if (curr_seg_cmd->cmd == LC_DYLD_EXPORTS_TRIE) {
|
||||
exports_trie_cmd = (struct linkedit_data_command *)curr_seg_cmd;
|
||||
} else if (curr_seg_cmd->cmd == LC_DYLD_CHAINED_FIXUPS) {
|
||||
chained_fixups_cmd = (struct linkedit_data_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;
|
||||
if (!is_runtime_mode) {
|
||||
// as mmap, all segment is close
|
||||
uintptr_t linkedit_segment_vmaddr = linkedit_segment->fileoff;
|
||||
linkedit_base = (uintptr_t)slide + linkedit_segment_vmaddr - linkedit_segment->fileoff;
|
||||
}
|
||||
|
||||
vm_region_start = segments[0]->vmaddr;
|
||||
// skip __LINKEDIT
|
||||
if (strcmp(segments[0]->segname, "__LINKEDIT") == 0) {
|
||||
vm_region_start = segments[1]->vmaddr;
|
||||
}
|
||||
vm_region_end = segments[segments_count - 1]->vmaddr + segments[segments_count - 1]->vmsize;
|
||||
vmaddr = vm_region_start;
|
||||
vmsize = vm_region_end - vm_region_start;
|
||||
|
||||
this->text_seg = text_segment;
|
||||
this->text_exec_seg = text_exec_segment;
|
||||
this->data_seg = data_segment;
|
||||
this->data_const_seg = data_const_segment;
|
||||
this->linkedit_seg = linkedit_segment;
|
||||
|
||||
this->symtab_cmd = symtab_cmd;
|
||||
this->dysymtab_cmd = dysymtab_cmd;
|
||||
this->dyld_info_cmd = dyld_info_cmd;
|
||||
this->exports_trie_cmd = exports_trie_cmd;
|
||||
this->chained_fixups_cmd = chained_fixups_cmd;
|
||||
|
||||
this->slide = slide;
|
||||
this->linkedit_base = linkedit_base;
|
||||
|
||||
this->symtab = (nlist_t *)(this->linkedit_base + this->symtab_cmd->symoff);
|
||||
this->strtab = (char *)(this->linkedit_base + this->symtab_cmd->stroff);
|
||||
this->indirect_symtab = (uint32_t *)(this->linkedit_base + this->dysymtab_cmd->indirectsymoff);
|
||||
}
|
||||
|
||||
uintptr_t macho_ctx_t::iterate_symbol_table(const char *symbol_name_pattern) {
|
||||
nlist_t *symtab = this->symtab;
|
||||
uint32_t symtab_count = this->symtab_cmd->nsyms;
|
||||
char *strtab = this->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
|
||||
printf("> %s", symbol_name);
|
||||
#endif
|
||||
if (strcmp(symbol_name_pattern, symbol_name) == 0) {
|
||||
return symtab[i].n_value;
|
||||
}
|
||||
if (symbol_name[0] == '_') {
|
||||
if (strcmp(symbol_name_pattern, &symbol_name[1]) == 0) {
|
||||
return symtab[i].n_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
// bool MachOLoaded::findExportedSymbol
|
||||
// MachOLoaded::trieWalk
|
||||
uint8_t *tail_walk(const uint8_t *start, const uint8_t *end, const char *symbol) {
|
||||
uint32_t visitedNodeOffsets[128];
|
||||
int visitedNodeOffsetCount = 0;
|
||||
visitedNodeOffsets[visitedNodeOffsetCount++] = 0;
|
||||
const uint8_t *p = start;
|
||||
while (p < end) {
|
||||
uint64_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)) {
|
||||
return (uint8_t *)p;
|
||||
}
|
||||
const uint8_t *children = p + terminalSize;
|
||||
if (children > end) {
|
||||
// diag.error("malformed trie node, terminalSize=0x%llX extends past end of trie\n", terminalSize);
|
||||
return NULL;
|
||||
}
|
||||
uint8_t childrenRemaining = *children++;
|
||||
p = children;
|
||||
uint64_t nodeOffset = 0;
|
||||
|
||||
for (; childrenRemaining > 0; --childrenRemaining) {
|
||||
const char *ss = symbol;
|
||||
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) {
|
||||
// diag.error("malformed trie node, child node extends past end of trie\n");
|
||||
return nullptr;
|
||||
}
|
||||
} 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)) {
|
||||
// diag.error("malformed trie child, nodeOffset=0x%llX out of range\n", nodeOffset);
|
||||
return nullptr;
|
||||
}
|
||||
symbol = ss;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeOffset != 0) {
|
||||
if (nodeOffset > (uint64_t)(end - start)) {
|
||||
// diag.error("malformed trie child, nodeOffset=0x%llX out of range\n", nodeOffset);
|
||||
return NULL;
|
||||
}
|
||||
for (int i = 0; i < visitedNodeOffsetCount; ++i) {
|
||||
if (visitedNodeOffsets[i] == nodeOffset) {
|
||||
// diag.error("malformed trie child, cycle to nodeOffset=0x%llX\n", nodeOffset);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
visitedNodeOffsets[visitedNodeOffsetCount++] = (uint32_t)nodeOffset;
|
||||
p = &start[nodeOffset];
|
||||
} else
|
||||
p = end;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uintptr_t macho_ctx_t::iterate_exported_symbol(const char *symbol_name, uint64_t *out_flags) {
|
||||
if (this->text_seg == NULL || this->linkedit_seg == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dyld_info_command *dyld_info_cmd = this->dyld_info_cmd;
|
||||
struct linkedit_data_command *exports_trie_cmd = this->exports_trie_cmd;
|
||||
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;
|
||||
|
||||
void *exports = (void *)(this->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 *)tail_walk(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 (out_flags)
|
||||
*out_flags = flags;
|
||||
if (flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
|
||||
const uint64_t ordinal = read_uleb128(&p, exports_end);
|
||||
const char *importedName = (const char *)p;
|
||||
if (importedName[0] == '\0') {
|
||||
importedName = symbol_name;
|
||||
return 0;
|
||||
}
|
||||
// trick
|
||||
// printf("reexported symbol: %s\n", importedName);
|
||||
return (uintptr_t)importedName;
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
uintptr_t macho_ctx_t::symbol_resolve_options(const char *symbol_name_pattern, resolve_symbol_type_t type) {
|
||||
if (type & RESOLVE_SYMBOL_TYPE_SYMBOL_TABLE) {
|
||||
uintptr_t result = iterate_symbol_table(symbol_name_pattern);
|
||||
if (result) {
|
||||
result = result + (this->is_runtime_mode ? this->slide : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (type & RESOLVE_SYMBOL_TYPE_EXPORTED) {
|
||||
// binary exported table(uleb128)
|
||||
uint64_t flags;
|
||||
uintptr_t result = iterate_exported_symbol(symbol_name_pattern, &flags);
|
||||
if (result) {
|
||||
switch (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) {
|
||||
case EXPORT_SYMBOL_FLAGS_KIND_REGULAR: {
|
||||
result += (uintptr_t)this->header;
|
||||
} break;
|
||||
case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL: {
|
||||
result += (uintptr_t)this->header;
|
||||
} break;
|
||||
case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: {
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t macho_ctx_t::symbol_resolve(const char *symbol_name_pattern) {
|
||||
return symbol_resolve_options(symbol_name_pattern, RESOLVE_SYMBOL_TYPE_ALL);
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.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
|
||||
|
||||
intptr_t read_sleb128(const uint8_t **pp, const uint8_t *end);
|
||||
|
||||
uintptr_t read_uleb128(const uint8_t **pp, const uint8_t *end);
|
||||
|
||||
typedef enum {
|
||||
RESOLVE_SYMBOL_TYPE_SYMBOL_TABLE = 1 << 0,
|
||||
RESOLVE_SYMBOL_TYPE_EXPORTED = 1 << 1,
|
||||
RESOLVE_SYMBOL_TYPE_ALL = RESOLVE_SYMBOL_TYPE_SYMBOL_TABLE | RESOLVE_SYMBOL_TYPE_EXPORTED
|
||||
} resolve_symbol_type_t;
|
||||
|
||||
struct macho_ctx_t {
|
||||
bool is_runtime_mode;
|
||||
|
||||
mach_header_t *header;
|
||||
|
||||
uintptr_t vmaddr;
|
||||
size_t vmsize;
|
||||
uintptr_t vm_region_start;
|
||||
uintptr_t vm_region_end;
|
||||
|
||||
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;
|
||||
struct linkedit_data_command *exports_trie_cmd;
|
||||
struct linkedit_data_command *chained_fixups_cmd;
|
||||
|
||||
nlist_t *symtab;
|
||||
char *strtab;
|
||||
uint32_t *indirect_symtab;
|
||||
|
||||
explicit macho_ctx_t(mach_header_t *header, bool is_runtime_mode = true) {
|
||||
init(header, is_runtime_mode);
|
||||
}
|
||||
|
||||
void init(mach_header_t *header, bool is_runtime_mode);
|
||||
|
||||
uintptr_t iterate_symbol_table(const char *symbol_name_pattern);
|
||||
|
||||
uintptr_t iterate_exported_symbol(const char *symbol_name, uint64_t *out_flags);
|
||||
|
||||
uintptr_t symbol_resolve_options(const char *symbol_name_pattern, resolve_symbol_type_t type);
|
||||
|
||||
uintptr_t symbol_resolve(const char *symbol_name_pattern);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uintptr_t macho_iterate_symbol_table(char *name_pattern, nlist_t *symtab, uint32_t symtab_count, char *strtab);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,68 @@
|
||||
#include "macho_file_symbol_resolver.h"
|
||||
|
||||
#include "SymbolResolver/mmap_file_util.h"
|
||||
|
||||
#include <mach-o/fat.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
|
||||
uintptr_t macho_file_memory_symbol_resolve(cpu_type_t in_cputype, cpu_subtype_t in_cpusubtype, const uint8_t *file_mem,
|
||||
char *symbol_name_pattern) {
|
||||
|
||||
mach_header_t *header = (mach_header_t *)file_mem;
|
||||
struct fat_header *fh = (struct fat_header *)file_mem;
|
||||
if (fh->magic == OSSwapBigToHostInt32(FAT_MAGIC)) {
|
||||
const struct fat_arch *archs = (struct fat_arch *)(((uintptr_t)fh) + sizeof(fat_header));
|
||||
mach_header_t *header_arm64 = NULL;
|
||||
mach_header_t *header_arm64e = NULL;
|
||||
mach_header_t *header_x64 = NULL;
|
||||
for (size_t i = 0; i < OSSwapBigToHostInt32(fh->nfat_arch); i++) {
|
||||
uint64_t offset;
|
||||
uint64_t len;
|
||||
cpu_type_t cputype = (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype);
|
||||
cpu_subtype_t cpusubtype = (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype);
|
||||
offset = OSSwapBigToHostInt32(archs[i].offset);
|
||||
len = OSSwapBigToHostInt32(archs[i].size);
|
||||
if (cputype == CPU_TYPE_X86_64) {
|
||||
header_x64 = (mach_header_t *)&file_mem[offset];
|
||||
} else if (cputype == CPU_TYPE_ARM64 && (cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E) {
|
||||
header_arm64e = (mach_header_t *)&file_mem[offset];
|
||||
} else if (cputype == CPU_TYPE_ARM64) {
|
||||
header_arm64 = (mach_header_t *)&file_mem[offset];
|
||||
}
|
||||
|
||||
if ((cputype == in_cputype) && ((cpusubtype & in_cpusubtype) == in_cpusubtype)) {
|
||||
header = (mach_header_t *)&file_mem[offset];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (header == (mach_header_t *)file_mem) {
|
||||
if (in_cputype == 0 && in_cpusubtype == 0) {
|
||||
#if defined(__arm64__) || defined(__aarch64__)
|
||||
header = header_arm64e ? header_arm64e : header_arm64;
|
||||
#else
|
||||
header = header_x64;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macho_ctx_t ctx(header, false);
|
||||
return ctx.symbol_resolve_options(symbol_name_pattern, RESOLVE_SYMBOL_TYPE_SYMBOL_TABLE);
|
||||
}
|
||||
|
||||
uintptr_t macho_file_symbol_resolve(cpu_type_t cpu, cpu_subtype_t subtype, const char *file,
|
||||
char *symbol_name_pattern) {
|
||||
|
||||
#if defined(COMPILE_WITH_NO_STDLIB)
|
||||
return 0;
|
||||
#endif
|
||||
MmapFileManager mng(file);
|
||||
auto mmap_buffer = mng.map();
|
||||
if (!mmap_buffer) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return macho_file_memory_symbol_resolve(cpu, subtype, mmap_buffer, symbol_name_pattern);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "macho_ctx.h"
|
||||
|
||||
uintptr_t macho_file_memory_symbol_resolve(cpu_type_t cpu, cpu_subtype_t subtype, const uint8_t *file_mem,
|
||||
char *symbol_name_pattern);
|
||||
|
||||
uintptr_t macho_file_symbol_resolve(cpu_type_t cpu, cpu_subtype_t subtype, const char *file, char *symbol_name_pattern);
|
@ -0,0 +1,560 @@
|
||||
/* -*- 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 <stdint.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
|
||||
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 imagesOffsetOld; // UNUSED: moved to imagesOffset to prevent older dsc_extarctors from crashing
|
||||
uint32_t imagesCountOld; // UNUSED: moved to imagesCount to prevent older dsc_extarctors from crashing
|
||||
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, 2 for multi-cache
|
||||
uint32_t branchPoolsOffset; // file offset to table of uint64_t pool addresses
|
||||
uint32_t branchPoolsCount; // number of uint64_t entries
|
||||
uint64_t dyldInCacheMH; // (unslid) address of mach_header of dyld in cache
|
||||
uint64_t dyldInCacheEntry; // (unslid) address of entry point (_dyld_start) of dyld in cache
|
||||
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 required to map the cache and all subCaches, if any
|
||||
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
|
||||
uint64_t dylibsPBLStateArrayAddrUnused; // unused
|
||||
uint64_t dylibsPBLSetAddr; // (unslid) address of PrebuiltLoaderSet of all cached dylibs
|
||||
uint64_t programsPBLSetPoolAddr; // (unslid) address of pool of PrebuiltLoaderSet for each program
|
||||
uint64_t programsPBLSetPoolSize; // size of pool of PrebuiltLoaderSet for each program
|
||||
uint64_t programTrieAddr; // (unslid) address of trie mapping program path to PrebuiltLoaderSet
|
||||
uint32_t programTrieSize;
|
||||
uint32_t osVersion; // OS Version of dylibs in this cache for the main platform
|
||||
uint32_t altPlatform; // e.g. iOSMac on macOS
|
||||
uint32_t altOsVersion; // e.g. 14.0 for iOSMac
|
||||
uint64_t swiftOptsOffset; // VM offset from cache_header* to Swift optimizations header
|
||||
uint64_t swiftOptsSize; // size of Swift optimizations header
|
||||
uint32_t subCacheArrayOffset; // file offset to first dyld_subcache_entry
|
||||
uint32_t subCacheArrayCount; // number of subCache entries
|
||||
uint8_t symbolFileUUID[16]; // unique value for the shared cache file containing unmapped local symbols
|
||||
uint64_t rosettaReadOnlyAddr; // (unslid) address of the start of where Rosetta can add read-only/executable data
|
||||
uint64_t rosettaReadOnlySize; // maximum size of the Rosetta read-only/executable region
|
||||
uint64_t rosettaReadWriteAddr; // (unslid) address of the start of where Rosetta can add read-write data
|
||||
uint64_t rosettaReadWriteSize; // maximum size of the Rosetta read-write region
|
||||
uint32_t imagesOffset; // file offset to first dyld_cache_image_info
|
||||
uint32_t imagesCount; // number of dyld_cache_image_info entries
|
||||
uint32_t cacheSubType; // 0 for development, 1 for production, when cacheType is multi-cache(2)
|
||||
uint64_t objcOptsOffset; // VM offset from cache_header* to ObjC optimizations header
|
||||
uint64_t objcOptsSize; // size of ObjC optimizations header
|
||||
uint64_t cacheAtlasOffset; // VM offset from cache_header* to embedded cache atlas for process introspection
|
||||
uint64_t cacheAtlasSize; // size of embedded cache atlas
|
||||
uint64_t dynamicDataOffset; // VM offset from cache_header* to the location of dyld_cache_dynamic_data_header
|
||||
uint64_t dynamicDataMaxSize; // maximum size of space reserved from dynamic data
|
||||
};
|
||||
|
||||
// Uncomment this and check the build errors for the current mapping offset to check against when adding new fields.
|
||||
// template<size_t size> class A { int x[-size]; }; A<sizeof(dyld_cache_header)> 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,
|
||||
DYLD_CACHE_MAPPING_TEXT_STUBS = 1 << 3U,
|
||||
DYLD_CACHE_DYNAMIC_CONFIG_DATA = 1 << 4U,
|
||||
};
|
||||
|
||||
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_local_symbols_entry_64
|
||||
{
|
||||
uint64_t dylibOffset; // offset in cache buffer 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_subcache_entry_v1
|
||||
{
|
||||
uint8_t uuid[16]; // The UUID of the subCache file
|
||||
uint64_t cacheVMOffset; // The offset of this subcache from the main cache base address
|
||||
};
|
||||
|
||||
struct dyld_subcache_entry
|
||||
{
|
||||
uint8_t uuid[16]; // The UUID of the subCache file
|
||||
uint64_t cacheVMOffset; // The offset of this subcache from the main cache base address
|
||||
char fileSuffix[32]; // The file name suffix of the subCache file e.g. ".25.data", ".03.development"
|
||||
};
|
||||
|
||||
// This struct is a small piece of dynamic data that can be included in the shared region, and contains configuration
|
||||
// data about the shared cache in use by the process. It is located
|
||||
struct dyld_cache_dynamic_data_header
|
||||
{
|
||||
char magic[16]; // e.g. "dyld_data v0"
|
||||
uint64_t fsId; // The fsid_t of the shared cache being used by a process
|
||||
uint64_t fsObjId; // The fs_obj_id_t of the shared cache being used by a process
|
||||
};
|
||||
|
||||
// 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/"
|
||||
|
||||
#define DRIVERKIT_DYLD_SHARED_CACHE_DIR "/System/DriverKit/System/Library/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"
|
||||
|
||||
#define DYLD_SHARED_CACHE_DYNAMIC_DATA_MAGIC "dyld_data v0"
|
||||
|
||||
static const char* cryptexPrefixes[] = {
|
||||
"/System/Volumes/Preboot/Cryptexes/OS/",
|
||||
"/private/preboot/Cryptexes/OS/",
|
||||
"/System/Cryptexes/OS"
|
||||
};
|
||||
|
||||
static const uint64_t kDyldSharedCacheTypeDevelopment = 0;
|
||||
static const uint64_t kDyldSharedCacheTypeProduction = 1;
|
||||
static const uint64_t kDyldSharedCacheTypeUniversal = 2;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // __DYLD_CACHE_FORMAT__
|
||||
|
||||
|
@ -0,0 +1,183 @@
|
||||
#include "shared_cache_ctx.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
|
||||
#include "logging/logging.h"
|
||||
|
||||
#include "mmap_file_util.h"
|
||||
|
||||
typedef uintptr_t addr_t;
|
||||
|
||||
extern "C" {
|
||||
extern const char *dyld_shared_cache_file_path();
|
||||
extern int __shared_region_check_np(uint64_t *startaddress);
|
||||
}
|
||||
|
||||
const char *shared_cache_get_file_path() {
|
||||
return dyld_shared_cache_file_path();
|
||||
}
|
||||
|
||||
struct dyld_cache_header *shared_cache_get_load_addr() {
|
||||
addr_t shared_cache_base = 0;
|
||||
if (__shared_region_check_np((uint64_t *)&shared_cache_base) != 0) {
|
||||
WARN_LOG("__shared_region_check_np failed");
|
||||
}
|
||||
|
||||
if (shared_cache_base)
|
||||
return (struct dyld_cache_header *)shared_cache_base;
|
||||
|
||||
// task info
|
||||
task_dyld_info_data_t task_dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
kern_return_t ret = task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count);
|
||||
if (ret != KERN_SUCCESS) {
|
||||
ERROR_LOG("task_info failed, ret: %d", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get dyld load address
|
||||
auto *infos = (struct dyld_all_image_infos *)(uintptr_t)task_dyld_info.all_image_info_addr;
|
||||
auto *shared_cache = (struct dyld_cache_header *)infos->sharedCacheBaseAddress;
|
||||
return shared_cache;
|
||||
}
|
||||
|
||||
int shared_cache_load_symbols(shared_cache_ctx_t *ctx) {
|
||||
uint64_t localSymbolsOffset = 0;
|
||||
|
||||
bool latest_shared_cache_format = true;
|
||||
|
||||
const char *shared_cache_path = shared_cache_get_file_path();
|
||||
char shared_cache_symbols_path[4096] = {0};
|
||||
{
|
||||
strcat(shared_cache_symbols_path, shared_cache_path);
|
||||
strcat(shared_cache_symbols_path, ".symbols");
|
||||
}
|
||||
|
||||
auto mmapSharedCacheSymbolsMng = new MmapFileManager(shared_cache_symbols_path);
|
||||
auto mmap_buffer = mmapSharedCacheSymbolsMng->map();
|
||||
if (mmap_buffer) { // iphoneos >= 15.0, which has .symbols file
|
||||
ctx->mmap_shared_cache = (struct dyld_cache_header *)mmap_buffer;
|
||||
|
||||
localSymbolsOffset = ctx->mmap_shared_cache->localSymbolsOffset;
|
||||
} else {
|
||||
// iphoneos < 15.0, which has no .symbols file
|
||||
auto mmapSharedCacheMng = new MmapFileManager(shared_cache_symbols_path);
|
||||
|
||||
auto runtime_shared_cache = ctx->runtime_shared_cache;
|
||||
uint64_t mmap_length = runtime_shared_cache->localSymbolsSize;
|
||||
uint64_t mmap_offset = runtime_shared_cache->localSymbolsOffset;
|
||||
|
||||
if (mmap_length == 0)
|
||||
return -1;
|
||||
|
||||
auto mmap_buffer = mmapSharedCacheMng->map_options(mmap_length, mmap_offset);
|
||||
if (!mmap_buffer) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fake shared cache header
|
||||
auto mmap_shared_cache =
|
||||
(struct dyld_cache_header *)((addr_t)mmap_buffer - runtime_shared_cache->localSymbolsOffset);
|
||||
ctx->mmap_shared_cache = mmap_shared_cache;
|
||||
|
||||
localSymbolsOffset = runtime_shared_cache->localSymbolsOffset;
|
||||
|
||||
latest_shared_cache_format = false;
|
||||
}
|
||||
ctx->latest_shared_cache_format = latest_shared_cache_format;
|
||||
|
||||
{
|
||||
auto mmap_shared_cache = ctx->mmap_shared_cache;
|
||||
auto localInfo = (struct dyld_cache_local_symbols_info *)((char *)mmap_shared_cache + localSymbolsOffset);
|
||||
ctx->local_symbols_info = localInfo;
|
||||
|
||||
if (ctx->latest_shared_cache_format) {
|
||||
auto localEntries_64 = (struct dyld_cache_local_symbols_entry_64 *)((char *)localInfo + localInfo->entriesOffset);
|
||||
ctx->local_symbols_entries_64 = localEntries_64;
|
||||
} else {
|
||||
auto localEntries = (struct dyld_cache_local_symbols_entry *)((char *)localInfo + localInfo->entriesOffset);
|
||||
ctx->local_symbols_entries = localEntries;
|
||||
}
|
||||
|
||||
ctx->symtab = (nlist_t *)((char *)localInfo + localInfo->nlistOffset);
|
||||
ctx->strtab = ((char *)localInfo) + localInfo->stringsOffset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shared_cache_ctx_init(shared_cache_ctx_t *ctx) {
|
||||
memset(ctx, 0, sizeof(shared_cache_ctx_t));
|
||||
|
||||
auto runtime_shared_cache = shared_cache_get_load_addr();
|
||||
if (!runtime_shared_cache) {
|
||||
return -1;
|
||||
}
|
||||
ctx->runtime_shared_cache = runtime_shared_cache;
|
||||
|
||||
// shared cache slide
|
||||
auto 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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
addr_t region_start = runtime_shared_cache->sharedRegionStart + ctx->runtime_slide;
|
||||
addr_t region_end = region_start + runtime_shared_cache->sharedRegionSize;
|
||||
if (addr >= region_start && addr < region_end)
|
||||
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) {
|
||||
uint64_t textOffsetInCache = (uint64_t)image_header - (uint64_t)ctx->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->latest_shared_cache_format) {
|
||||
if (ctx->local_symbols_entries_64[i].dylibOffset == textOffsetInCache) {
|
||||
uint32_t localNlistStart = ctx->local_symbols_entries_64[i].nlistStartIndex;
|
||||
localNlistCount = ctx->local_symbols_entries_64[i].nlistCount;
|
||||
localNlists = &ctx->symtab[localNlistStart];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
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];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
INFO_LOG("dyld image: %s", image_name);
|
||||
#endif
|
||||
}
|
||||
*out_symtab = localNlists;
|
||||
*out_symtab_count = (uint32_t)localNlistCount;
|
||||
*out_strtab = (char *)ctx->strtab;
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
#include <sys/types.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
|
||||
#include "shared-cache/dyld_cache_format.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
|
||||
|
||||
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;
|
||||
|
||||
bool latest_shared_cache_format;
|
||||
struct dyld_cache_local_symbols_info *local_symbols_info;
|
||||
struct dyld_cache_local_symbols_entry *local_symbols_entries;
|
||||
struct dyld_cache_local_symbols_entry_64 *local_symbols_entries_64;
|
||||
|
||||
nlist_t *symtab;
|
||||
char *strtab;
|
||||
} shared_cache_ctx_t;
|
||||
|
||||
int shared_cache_ctx_init(shared_cache_ctx_t *ctx);
|
||||
|
||||
int shared_cache_load_symbols(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);
|
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
struct MmapFileManager {
|
||||
const char *file_;
|
||||
uint8_t *mmap_buffer;
|
||||
size_t mmap_buffer_size;
|
||||
|
||||
explicit MmapFileManager(const char *file) : file_(file), mmap_buffer(nullptr) {
|
||||
}
|
||||
|
||||
~MmapFileManager() {
|
||||
if (mmap_buffer) {
|
||||
munmap((void *)mmap_buffer, mmap_buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *map() {
|
||||
size_t file_size = 0;
|
||||
{
|
||||
struct stat s;
|
||||
int rt = stat(file_, &s);
|
||||
if (rt != 0) {
|
||||
// printf("mmap %s failed\n", file_);
|
||||
return NULL;
|
||||
}
|
||||
file_size = s.st_size;
|
||||
}
|
||||
|
||||
return map_options(file_size, 0);
|
||||
}
|
||||
|
||||
uint8_t *map_options(size_t in_map_size, off_t in_map_off) {
|
||||
if (!mmap_buffer) {
|
||||
int fd = open(file_, O_RDONLY, 0);
|
||||
if (fd < 0) {
|
||||
// printf("%s open failed\n", file_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// auto align
|
||||
auto mmap_buffer = (uint8_t *)mmap(0, in_map_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, fd, in_map_off);
|
||||
if (mmap_buffer == MAP_FAILED) {
|
||||
// printf("mmap %s failed\n", file_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
this->mmap_buffer = mmap_buffer;
|
||||
this->mmap_buffer_size = in_map_size;
|
||||
}
|
||||
return mmap_buffer;
|
||||
}
|
||||
};
|
@ -0,0 +1,26 @@
|
||||
#include "SymbolResolver/dobby_symbol_resolver.h"
|
||||
#include "dobby/common.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#include "PlatformUtil/ProcessRuntimeUtility.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#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;
|
||||
}
|
3
app/src/main/cpp/Dobby/cmake/Macros.cmake
Normal file
3
app/src/main/cpp/Dobby/cmake/Macros.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
macro(SET_OPTION option value)
|
||||
set(${option} ${value} CACHE INTERNAL "" FORCE)
|
||||
endmacro()
|
29
app/src/main/cpp/Dobby/cmake/Util.cmake
Normal file
29
app/src/main/cpp/Dobby/cmake/Util.cmake
Normal file
@ -0,0 +1,29 @@
|
||||
# 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()
|
||||
|
||||
|
||||
function(get_absolute_path_list input_list output_list)
|
||||
set(absolute_list)
|
||||
foreach (file ${${input_list}})
|
||||
get_filename_component(absolute_file ${file} ABSOLUTE)
|
||||
list(APPEND absolute_list ${absolute_file})
|
||||
endforeach ()
|
||||
set(${output_list} ${absolute_list} PARENT_SCOPE)
|
||||
endfunction()
|
32
app/src/main/cpp/Dobby/cmake/auto_source_group.cmake
Normal file
32
app/src/main/cpp/Dobby/cmake/auto_source_group.cmake
Normal file
@ -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 ()
|
86
app/src/main/cpp/Dobby/cmake/build_environment_check.cmake
Normal file
86
app/src/main/cpp/Dobby/cmake/build_environment_check.cmake
Normal file
@ -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(DOBBY_BUILD_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 "")
|
55
app/src/main/cpp/Dobby/cmake/compiler_and_linker.cmake
Normal file
55
app/src/main/cpp/Dobby/cmake/compiler_and_linker.cmake
Normal file
@ -0,0 +1,55 @@
|
||||
# :< 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 ()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-stack-protector")
|
||||
|
||||
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}")
|
94
app/src/main/cpp/Dobby/cmake/dobby.xcode.source.cmake
Normal file
94
app/src/main/cpp/Dobby/cmake/dobby.xcode.source.cmake
Normal file
@ -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()
|
30
app/src/main/cpp/Dobby/cmake/platform/platform-darwin.cmake
Normal file
30
app/src/main/cpp/Dobby/cmake/platform/platform-darwin.cmake
Normal file
@ -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 DOBBY_BUILD_KERNEL_MODE))
|
||||
add_subdirectory(builtin-plugin/Dyld2HideLibrary)
|
||||
add_subdirectory(builtin-plugin/ObjcRuntimeHook)
|
||||
if (PROCESSOR.AARCH64)
|
||||
add_subdirectory(builtin-plugin/SupervisorCallMonitor)
|
||||
endif ()
|
||||
endif()
|
@ -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()
|
89
app/src/main/cpp/Dobby/docs/compile.md
Normal file
89
app/src/main/cpp/Dobby/docs/compile.md
Normal file
@ -0,0 +1,89 @@
|
||||
# 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(DOBBY_BUILD_EXAMPLE "Build example" OFF)
|
||||
|
||||
option(DOBBY_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.25.2 --llvm_dir=$HOME/opt/llvm-15.0.6
|
||||
```
|
||||
|
||||
#### Build for android
|
||||
|
||||
```
|
||||
# prepare and download cmake/llvm/ndk
|
||||
sh scripts/setup_linux_cross_compile.sh
|
||||
python3 scripts/platform_builder.py --platform=android --arch=all --cmake_dir=$HOME/opt/cmake-3.25.2 --llvm_dir=$HOME/opt/llvm-15.0.6 --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}
|
||||
$<TARGET_PROPERTY:dobby,INCLUDE_DIRECTORIES>
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(native-lib SHARED
|
||||
${DOBBY_DIR}/examples/socket_example.cc
|
||||
native-lib.cpp)
|
||||
```
|
18
app/src/main/cpp/Dobby/examples/CMakeLists.txt
Normal file
18
app/src/main/cpp/Dobby/examples/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
add_executable(socket_example
|
||||
main.cc
|
||||
socket_example.cc
|
||||
)
|
||||
|
||||
target_link_libraries(socket_example
|
||||
dobby
|
||||
logging
|
||||
)
|
||||
|
||||
|
||||
add_library(socket_example_lib SHARED
|
||||
socket_example.cc
|
||||
)
|
||||
|
||||
target_link_libraries(socket_example_lib
|
||||
dobby
|
||||
)
|
14
app/src/main/cpp/Dobby/examples/main.cc
Normal file
14
app/src/main/cpp/Dobby/examples/main.cc
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
|
||||
std::cout << "Start..." << std::endl;
|
||||
|
||||
sleep(100);
|
||||
return 0;
|
||||
}
|
212
app/src/main/cpp/Dobby/examples/socket_example.cc
Normal file
212
app/src/main/cpp/Dobby/examples/socket_example.cc
Normal file
@ -0,0 +1,212 @@
|
||||
#include "dobby.h"
|
||||
|
||||
#include "logging/logging.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
std::map<void *, const char *> *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) {
|
||||
INFO_LOG("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()) {
|
||||
INFO_LOG("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() {
|
||||
logger_set_options(0, 0, 0, LOG_LEVEL_DEBUG, false, false);
|
||||
|
||||
void *func = NULL;
|
||||
func_map = new std::map<void *, const char *>();
|
||||
for (int i = 0; i < sizeof(func_array) / sizeof(char *); ++i) {
|
||||
func = DobbySymbolResolver(NULL, func_array[i]);
|
||||
if (func == NULL) {
|
||||
INFO_LOG("func %s not resolve", func_array[i]);
|
||||
continue;
|
||||
}
|
||||
func_map->insert(std::pair<void *, const char *>(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 <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#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);
|
||||
INFO_LOG("[server] %s", buffer);
|
||||
|
||||
send(new_socket, hello, strlen(hello), 0);
|
||||
INFO_LOG("[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);
|
||||
INFO_LOG("[client] Hello message sent");
|
||||
|
||||
int ret = recv(sock, buffer, 1024, 0);
|
||||
INFO_LOG("[client] %s", buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
1
app/src/main/cpp/Dobby/external/TINYSTL/README
vendored
Normal file
1
app/src/main/cpp/Dobby/external/TINYSTL/README
vendored
Normal file
@ -0,0 +1 @@
|
||||
ref: https://github.com/mendsley/tinystl
|
1
app/src/main/cpp/Dobby/external/TINYSTL/algorithm.h
vendored
Normal file
1
app/src/main/cpp/Dobby/external/TINYSTL/algorithm.h
vendored
Normal file
@ -0,0 +1 @@
|
||||
#pragma once
|
49
app/src/main/cpp/Dobby/external/TINYSTL/allocator.h
vendored
Normal file
49
app/src/main/cpp/Dobby/external/TINYSTL/allocator.h
vendored
Normal file
@ -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 <TINYSTL/stddef.h>
|
||||
|
||||
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
|
310
app/src/main/cpp/Dobby/external/TINYSTL/buffer.h
vendored
Normal file
310
app/src/main/cpp/Dobby/external/TINYSTL/buffer.h
vendored
Normal file
@ -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 <TINYSTL/allocator.h>
|
||||
#include <TINYSTL/new.h>
|
||||
#include <TINYSTL/traits.h>
|
||||
|
||||
namespace tinystl {
|
||||
|
||||
template<typename T, typename Alloc = TINYSTL_ALLOCATOR>
|
||||
struct buffer {
|
||||
T* first;
|
||||
T* last;
|
||||
T* capacity;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_destroy_range_traits(T* first, T* last, pod_traits<T, false>) {
|
||||
for (; first < last; ++first)
|
||||
first->~T();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_destroy_range_traits(T*, T*, pod_traits<T, true>) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_destroy_range(T* first, T* last) {
|
||||
buffer_destroy_range_traits(first, last, pod_traits<T>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_fill_urange_traits(T* first, T* last, pod_traits<T, false>) {
|
||||
for (; first < last; ++first)
|
||||
new(placeholder(), first) T();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_fill_urange_traits(T* first, T* last, pod_traits<T, true>) {
|
||||
for (; first < last; ++first)
|
||||
*first = T();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_fill_urange_traits(T* first, T* last, const T& value, pod_traits<T, false>) {
|
||||
for (; first < last; ++first)
|
||||
new(placeholder(), first) T(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_fill_urange_traits(T* first, T* last, const T& value, pod_traits<T, true>) {
|
||||
for (; first < last; ++first)
|
||||
*first = value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_move_urange_traits(T* dest, T* first, T* last, pod_traits<T, false>) {
|
||||
for (T* it = first; it != last; ++it, ++dest)
|
||||
move_construct(dest, *it);
|
||||
buffer_destroy_range(first, last);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_move_urange_traits(T* dest, T* first, T* last, pod_traits<T, true>) {
|
||||
for (; first != last; ++first, ++dest)
|
||||
*dest = *first;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_bmove_urange_traits(T* dest, T* first, T* last, pod_traits<T, false>) {
|
||||
dest += (last - first);
|
||||
for (T* it = last; it != first; --it, --dest) {
|
||||
move_construct(dest - 1, *(it - 1));
|
||||
buffer_destroy_range(it - 1, it);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_bmove_urange_traits(T* dest, T* first, T* last, pod_traits<T, true>) {
|
||||
dest += (last - first);
|
||||
for (T* it = last; it != first; --it, --dest)
|
||||
*(dest - 1) = *(it - 1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_move_urange(T* dest, T* first, T* last) {
|
||||
buffer_move_urange_traits(dest, first, last, pod_traits<T>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_bmove_urange(T* dest, T* first, T* last) {
|
||||
buffer_bmove_urange_traits(dest, first, last, pod_traits<T>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_fill_urange(T* first, T* last) {
|
||||
buffer_fill_urange_traits(first, last, pod_traits<T>());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void buffer_fill_urange(T* first, T* last, const T& value) {
|
||||
buffer_fill_urange_traits(first, last, value, pod_traits<T>());
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
static inline void buffer_init(buffer<T, Alloc>* b) {
|
||||
b->first = b->last = b->capacity = 0;
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
static inline void buffer_destroy(buffer<T, Alloc>* b) {
|
||||
buffer_destroy_range(b->first, b->last);
|
||||
Alloc::static_deallocate(b->first, (size_t)((char*)b->capacity - (char*)b->first));
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
static inline void buffer_reserve(buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline void buffer_resize(buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline void buffer_resize(buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline void buffer_shrink_to_fit(buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline void buffer_clear(buffer<T, Alloc>* b) {
|
||||
buffer_destroy_range(b->first, b->last);
|
||||
b->last = b->first;
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
static inline T* buffer_insert_common(buffer<T, Alloc>* 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<typename T, typename Alloc, typename Param>
|
||||
static inline void buffer_insert(buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline void buffer_insert(buffer<T, Alloc>* 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<typename T, typename Alloc, typename Param>
|
||||
static inline void buffer_append(buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline void buffer_append(buffer<T, Alloc>* b) {
|
||||
if (b->capacity != b->last) {
|
||||
new(placeholder(), b->last) T();
|
||||
++b->last;
|
||||
} else {
|
||||
buffer_insert(b, b->last, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
static inline T* buffer_erase(buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline T* buffer_erase_unordered(buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline void buffer_swap(buffer<T, Alloc>* b, buffer<T, Alloc>* 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<typename T, typename Alloc>
|
||||
static inline void buffer_move(buffer<T, Alloc>* dst, buffer<T, Alloc>* src) {
|
||||
dst->first = src->first, dst->last = src->last, dst->capacity = src->capacity;
|
||||
src->first = src->last = src->capacity = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //TINYSTL_BUFFER_H
|
48
app/src/main/cpp/Dobby/external/TINYSTL/function.h
vendored
Normal file
48
app/src/main/cpp/Dobby/external/TINYSTL/function.h
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
namespace tinystl {
|
||||
|
||||
template <typename T> class function;
|
||||
|
||||
template <typename Return, typename... Args> class function<Return(Args...)> {
|
||||
public:
|
||||
function() {
|
||||
}
|
||||
|
||||
template <typename T> function(T functor) {
|
||||
m_func = [](const void *user, Args... args) -> Return {
|
||||
const T &func = *static_cast<const T *>(user);
|
||||
return func(static_cast<Args &&>(args)...);
|
||||
};
|
||||
|
||||
m_dtor = [](void *user) {
|
||||
T &func = *static_cast<T *>(user);
|
||||
func.~T();
|
||||
};
|
||||
|
||||
new (tinystl::placeholder(), m_storage) T(static_cast<T &&>(functor));
|
||||
}
|
||||
|
||||
~function() {
|
||||
if (m_dtor)
|
||||
m_dtor(m_storage);
|
||||
}
|
||||
|
||||
Return operator()(Args... args) const {
|
||||
return m_func(m_storage, static_cast<Args &&>(args)...);
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
return m_func != nullptr;
|
||||
}
|
||||
|
||||
using Func = Return (*)(const void *, Args...);
|
||||
Func m_func = nullptr;
|
||||
using Dtor = void (*)(void *);
|
||||
Dtor m_dtor = nullptr;
|
||||
union {
|
||||
void *m_storage[8];
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace tinystl
|
53
app/src/main/cpp/Dobby/external/TINYSTL/hash.h
vendored
Normal file
53
app/src/main/cpp/Dobby/external/TINYSTL/hash.h
vendored
Normal file
@ -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 <TINYSTL/stddef.h>
|
||||
|
||||
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<typename T>
|
||||
inline size_t hash(const T& value) {
|
||||
const size_t asint = (size_t)value;
|
||||
return hash_string((const char*)&asint, sizeof(asint));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
292
app/src/main/cpp/Dobby/external/TINYSTL/hash_base.h
vendored
Normal file
292
app/src/main/cpp/Dobby/external/TINYSTL/hash_base.h
vendored
Normal file
@ -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 <TINYSTL/stddef.h>
|
||||
#include <TINYSTL/traits.h>
|
||||
|
||||
namespace tinystl {
|
||||
|
||||
template<typename Key, typename Value>
|
||||
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<typename Key, typename Value>
|
||||
inline pair<Key, Value>::pair() {
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
inline pair<Key, Value>::pair(const pair& other)
|
||||
: first(other.first)
|
||||
, second(other.second)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
inline pair<Key, Value>::pair(pair&& other)
|
||||
: first(static_cast<Key&&>(other.first))
|
||||
, second(static_cast<Value&&>(other.second))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
inline pair<Key, Value>::pair(const Key& key, const Value& value)
|
||||
: first(key)
|
||||
, second(value)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
inline pair<Key, Value>::pair(Key&& key, Value&& value)
|
||||
: first(static_cast<Key&&>(key))
|
||||
, second(static_cast<Value&&>(value))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
inline pair<Key, Value>& pair<Key, Value>::operator=(const pair& other) {
|
||||
first = other.first;
|
||||
second = other.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
inline pair<Key, Value>& pair<Key, Value>::operator=(pair&& other) {
|
||||
first = static_cast<Key&&>(other.first);
|
||||
second = static_cast<Value&&>(other.second);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
static inline pair<typename remove_reference<Key>::type, typename remove_reference<Value>::type>
|
||||
make_pair(Key&& key, Value&& value) {
|
||||
return pair<typename remove_reference<Key>::type, typename remove_reference<Value>::type>(
|
||||
static_cast<Key&&>(key)
|
||||
, static_cast<Value&&>(value)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<typename Key, typename Value>
|
||||
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<typename Key, typename Value>
|
||||
inline unordered_hash_node<Key, Value>::unordered_hash_node(const Key& key, const Value& value)
|
||||
: first(key)
|
||||
, second(value)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
inline unordered_hash_node<Key, Value>::unordered_hash_node(Key&& key, Value&& value)
|
||||
: first(static_cast<Key&&>(key))
|
||||
, second(static_cast<Value&&>(value))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
struct unordered_hash_node<Key, void> {
|
||||
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<typename Key>
|
||||
inline unordered_hash_node<Key, void>::unordered_hash_node(const Key& key)
|
||||
: first(key)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
inline unordered_hash_node<Key, void>::unordered_hash_node(Key&& key)
|
||||
: first(static_cast<Key&&>(key))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
static inline void unordered_hash_node_insert(unordered_hash_node<Key, Value>* node, size_t hash, unordered_hash_node<Key, Value>** buckets, size_t nbuckets) {
|
||||
size_t bucket = hash & (nbuckets - 1);
|
||||
|
||||
unordered_hash_node<Key, Value>* 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<Key, Value>* 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<typename Key, typename Value>
|
||||
static inline void unordered_hash_node_erase(const unordered_hash_node<Key, Value>* where, size_t hash, unordered_hash_node<Key, Value>** buckets, size_t nbuckets) {
|
||||
size_t bucket = hash & (nbuckets - 1);
|
||||
|
||||
unordered_hash_node<Key, Value>* 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<typename Node>
|
||||
struct unordered_hash_iterator {
|
||||
Node* operator->() const;
|
||||
Node& operator*() const;
|
||||
Node* node;
|
||||
};
|
||||
|
||||
template<typename Node>
|
||||
struct unordered_hash_iterator<const Node> {
|
||||
|
||||
unordered_hash_iterator() {}
|
||||
unordered_hash_iterator(unordered_hash_iterator<Node> other)
|
||||
: node(other.node)
|
||||
{
|
||||
}
|
||||
|
||||
const Node* operator->() const;
|
||||
const Node& operator*() const;
|
||||
const Node* node;
|
||||
};
|
||||
|
||||
template<typename Key>
|
||||
struct unordered_hash_iterator<const unordered_hash_node<Key, void> > {
|
||||
const Key* operator->() const;
|
||||
const Key& operator*() const;
|
||||
unordered_hash_node<Key, void>* node;
|
||||
};
|
||||
|
||||
template<typename LNode, typename RNode>
|
||||
static inline bool operator==(const unordered_hash_iterator<LNode>& lhs, const unordered_hash_iterator<RNode>& rhs) {
|
||||
return lhs.node == rhs.node;
|
||||
}
|
||||
|
||||
template<typename LNode, typename RNode>
|
||||
static inline bool operator!=(const unordered_hash_iterator<LNode>& lhs, const unordered_hash_iterator<RNode>& rhs) {
|
||||
return lhs.node != rhs.node;
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
static inline void operator++(unordered_hash_iterator<Node>& lhs) {
|
||||
lhs.node = lhs.node->next;
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
inline Node* unordered_hash_iterator<Node>::operator->() const {
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
inline Node& unordered_hash_iterator<Node>::operator*() const {
|
||||
return *node;
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
inline const Node* unordered_hash_iterator<const Node>::operator->() const {
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
inline const Node& unordered_hash_iterator<const Node>::operator*() const {
|
||||
return *node;
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
inline const Key* unordered_hash_iterator<const unordered_hash_node<Key, void> >::operator->() const {
|
||||
return &node->first;
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
inline const Key& unordered_hash_iterator<const unordered_hash_node<Key, void> >::operator*() const {
|
||||
return node->first;
|
||||
}
|
||||
|
||||
template<typename Node, typename Key>
|
||||
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
|
44
app/src/main/cpp/Dobby/external/TINYSTL/new.h
vendored
Normal file
44
app/src/main/cpp/Dobby/external/TINYSTL/new.h
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*-
|
||||
* 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 <TINYSTL/stddef.h>
|
||||
|
||||
namespace tinystl {
|
||||
|
||||
struct placeholder {};
|
||||
} // namespace tinystl
|
||||
|
||||
inline void *operator new(size_t, tinystl::placeholder, void *ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
inline void operator delete(void *, tinystl::placeholder, void *) throw() {
|
||||
}
|
||||
|
||||
#endif
|
43
app/src/main/cpp/Dobby/external/TINYSTL/stddef.h
vendored
Normal file
43
app/src/main/cpp/Dobby/external/TINYSTL/stddef.h
vendored
Normal file
@ -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 <stddef.h>
|
||||
#endif
|
||||
|
||||
#endif
|
295
app/src/main/cpp/Dobby/external/TINYSTL/string.h
vendored
Normal file
295
app/src/main/cpp/Dobby/external/TINYSTL/string.h
vendored
Normal file
@ -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 <TINYSTL/allocator.h>
|
||||
#include <TINYSTL/stddef.h>
|
||||
#include <TINYSTL/hash.h>
|
||||
|
||||
namespace tinystl {
|
||||
|
||||
template<typename Allocator>
|
||||
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<typename allocator>
|
||||
inline basic_string<allocator>::basic_string()
|
||||
: m_first(m_buffer)
|
||||
, m_last(m_buffer)
|
||||
, m_capacity(m_buffer + c_nbuffer)
|
||||
{
|
||||
resize(0);
|
||||
}
|
||||
|
||||
template<typename allocator>
|
||||
inline basic_string<allocator>::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<typename allocator>
|
||||
inline basic_string<allocator>::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<typename allocator>
|
||||
inline basic_string<allocator>::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<typename allocator>
|
||||
inline basic_string<allocator>::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<typename allocator>
|
||||
inline basic_string<allocator>::~basic_string() {
|
||||
if (m_first != m_buffer)
|
||||
allocator::static_deallocate(m_first, m_capacity - m_first);
|
||||
}
|
||||
|
||||
template<typename allocator>
|
||||
inline basic_string<allocator>& basic_string<allocator>::operator=(const basic_string& other) {
|
||||
basic_string(other).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename allocator>
|
||||
inline basic_string<allocator>& basic_string<allocator>::operator=(basic_string&& other) {
|
||||
basic_string(static_cast<basic_string&&>(other)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename allocator>
|
||||
inline const char* basic_string<allocator>::c_str() const {
|
||||
return m_first;
|
||||
}
|
||||
|
||||
template<typename allocator>
|
||||
inline size_t basic_string<allocator>::size() const
|
||||
{
|
||||
return (size_t)(m_last - m_first);
|
||||
}
|
||||
|
||||
template<typename allocator>
|
||||
inline void basic_string<allocator>::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<typename allocator>
|
||||
inline void basic_string<allocator>::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<typename allocator>
|
||||
inline void basic_string<allocator>::clear() {
|
||||
resize(0);
|
||||
}
|
||||
|
||||
template<typename allocator>
|
||||
inline void basic_string<allocator>::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<typename allocator>
|
||||
inline void basic_string<allocator>::assign(const char* sz, size_t n) {
|
||||
clear();
|
||||
append(sz, sz+n);
|
||||
}
|
||||
|
||||
template<typename allocator>
|
||||
inline void basic_string<allocator>::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<typename allocator>
|
||||
inline void basic_string<allocator>::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<typename allocatorl, typename allocatorr>
|
||||
inline bool operator==(const basic_string<allocatorl>& lhs, const basic_string<allocatorr>& 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<typename allocator>
|
||||
static inline size_t hash(const basic_string<allocator>& value) {
|
||||
return hash_string(value.c_str(), value.size());
|
||||
}
|
||||
|
||||
typedef basic_string<TINYSTL_ALLOCATOR> string;
|
||||
}
|
||||
|
||||
#endif
|
147
app/src/main/cpp/Dobby/external/TINYSTL/string_view.h
vendored
Normal file
147
app/src/main/cpp/Dobby/external/TINYSTL/string_view.h
vendored
Normal file
@ -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 <TINYSTL/stddef.h>
|
||||
|
||||
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
|
100
app/src/main/cpp/Dobby/external/TINYSTL/traits.h
vendored
Normal file
100
app/src/main/cpp/Dobby/external/TINYSTL/traits.h
vendored
Normal file
@ -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 <TINYSTL/new.h>
|
||||
|
||||
#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<typename T, bool pod = TINYSTL_TRY_POD_OPTIMIZATION(T)> struct pod_traits {};
|
||||
|
||||
template<typename T, T t> struct swap_holder;
|
||||
|
||||
template<typename T>
|
||||
static inline void move_impl(T& a, T& b, ...) {
|
||||
a = b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void move_impl(T& a, T& b, T*, swap_holder<void (T::*)(T&), &T::swap>* = 0) {
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void move(T& a, T&b) {
|
||||
move_impl(a, b, (T*)0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void move_construct_impl(T* a, T& b, ...) {
|
||||
new(placeholder(), a) T(b);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void move_construct_impl(T* a, T& b, void*, swap_holder<void (T::*)(T&), &T::swap>* = 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<typename T>
|
||||
static inline void move_construct_impl(T* a, T& b, T*, typename T::tinystl_nomove_construct* = 0) {
|
||||
new(placeholder(), a) T(b);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void move_construct(T* a, T& b) {
|
||||
move_construct_impl(a, b, (T*)0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct remove_reference {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_reference<T&> {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_reference<T&&> {
|
||||
typedef T type;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
289
app/src/main/cpp/Dobby/external/TINYSTL/unordered_map.h
vendored
Normal file
289
app/src/main/cpp/Dobby/external/TINYSTL/unordered_map.h
vendored
Normal file
@ -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 <TINYSTL/allocator.h>
|
||||
#include <TINYSTL/buffer.h>
|
||||
#include <TINYSTL/hash.h>
|
||||
#include <TINYSTL/hash_base.h>
|
||||
|
||||
namespace tinystl {
|
||||
|
||||
template<typename Key, typename Value, typename Alloc = TINYSTL_ALLOCATOR>
|
||||
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<Key, Value> value_type;
|
||||
|
||||
typedef unordered_hash_iterator<const unordered_hash_node<Key, Value> > const_iterator;
|
||||
typedef unordered_hash_iterator<unordered_hash_node<Key, Value> > 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<iterator, bool> insert(const pair<Key, Value>& p);
|
||||
pair<iterator, bool> emplace(pair<Key, Value>&& 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<Key, Value>* pointer;
|
||||
|
||||
size_t m_size;
|
||||
tinystl::buffer<pointer, Alloc> m_buckets;
|
||||
};
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline unordered_map<Key, Value, Alloc>::unordered_map()
|
||||
: m_size(0)
|
||||
{
|
||||
buffer_init<pointer, Alloc>(&m_buckets);
|
||||
buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline unordered_map<Key, Value, Alloc>::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<pointer, Alloc>(&m_buckets);
|
||||
buffer_resize<pointer, Alloc>(&m_buckets, nbuckets, 0);
|
||||
|
||||
for (pointer it = *other.m_buckets.first; it; it = it->next) {
|
||||
unordered_hash_node<Key, Value>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, Value>))) unordered_hash_node<Key, Value>(it->first, it->second);
|
||||
newnode->next = newnode->prev = 0;
|
||||
|
||||
unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline unordered_map<Key, Value, Alloc>::unordered_map(unordered_map&& other)
|
||||
: m_size(other.m_size)
|
||||
{
|
||||
buffer_move(&m_buckets, &other.m_buckets);
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline unordered_map<Key, Value, Alloc>::~unordered_map() {
|
||||
if (m_buckets.first != m_buckets.last)
|
||||
clear();
|
||||
buffer_destroy<pointer, Alloc>(&m_buckets);
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline unordered_map<Key, Value, Alloc>& unordered_map<Key, Value, Alloc>::operator=(const unordered_map<Key, Value, Alloc>& other) {
|
||||
unordered_map<Key, Value, Alloc>(other).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline unordered_map<Key, Value, Alloc>& unordered_map<Key, Value, Alloc>::operator=(unordered_map&& other) {
|
||||
unordered_map(static_cast<unordered_map&&>(other)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline typename unordered_map<Key, Value, Alloc>::iterator unordered_map<Key, Value, Alloc>::begin() {
|
||||
iterator it;
|
||||
it.node = *m_buckets.first;
|
||||
return it;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline typename unordered_map<Key, Value, Alloc>::iterator unordered_map<Key, Value, Alloc>::end() {
|
||||
iterator it;
|
||||
it.node = 0;
|
||||
return it;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline typename unordered_map<Key, Value, Alloc>::const_iterator unordered_map<Key, Value, Alloc>::begin() const {
|
||||
const_iterator cit;
|
||||
cit.node = *m_buckets.first;
|
||||
return cit;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline typename unordered_map<Key, Value, Alloc>::const_iterator unordered_map<Key, Value, Alloc>::end() const {
|
||||
const_iterator cit;
|
||||
cit.node = 0;
|
||||
return cit;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline bool unordered_map<Key, Value, Alloc>::empty() const {
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline size_t unordered_map<Key, Value, Alloc>::size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline void unordered_map<Key, Value, Alloc>::clear() {
|
||||
pointer it = *m_buckets.first;
|
||||
while (it) {
|
||||
const pointer next = it->next;
|
||||
it->~unordered_hash_node<Key, Value>();
|
||||
Alloc::static_deallocate(it, sizeof(unordered_hash_node<Key, Value>));
|
||||
|
||||
it = next;
|
||||
}
|
||||
|
||||
m_buckets.last = m_buckets.first;
|
||||
buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline typename unordered_map<Key, Value, Alloc>::iterator unordered_map<Key, Value, Alloc>::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<typename Key, typename Value, typename Alloc>
|
||||
inline typename unordered_map<Key, Value, Alloc>::const_iterator unordered_map<Key, Value, Alloc>::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<typename Key, typename Value, typename Alloc>
|
||||
inline void unordered_map<Key, Value, Alloc>::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<pointer, Alloc>(&m_buckets, newnbuckets + 1, 0);
|
||||
unordered_hash_node<Key, Value>** 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<typename Key, typename Value, typename Alloc>
|
||||
inline pair<typename unordered_map<Key, Value, Alloc>::iterator, bool> unordered_map<Key, Value, Alloc>::insert(const pair<Key, Value>& p) {
|
||||
pair<iterator, bool> result;
|
||||
result.second = false;
|
||||
|
||||
result.first = find(p.first);
|
||||
if (result.first.node != 0)
|
||||
return result;
|
||||
|
||||
unordered_hash_node<Key, Value>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, Value>))) unordered_hash_node<Key, Value>(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<typename Key, typename Value, typename Alloc>
|
||||
inline pair<typename unordered_map<Key, Value, Alloc>::iterator, bool> unordered_map<Key, Value, Alloc>::emplace(pair<Key, Value>&& p) {
|
||||
pair<iterator, bool> 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<Key, Value>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, Value>))) unordered_hash_node<Key, Value>(static_cast<Key&&>(p.first), static_cast<Value&&>(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<typename Key, typename Value, typename Alloc>
|
||||
inline void unordered_map<Key, Value, Alloc>::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<Key, Value>();
|
||||
Alloc::static_deallocate((void*)where.node, sizeof(unordered_hash_node<Key, Value>));
|
||||
--m_size;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline Value& unordered_map<Key, Value, Alloc>::operator[](const Key& key) {
|
||||
return insert(pair<Key, Value>(key, Value())).first->second;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value, typename Alloc>
|
||||
inline void unordered_map<Key, Value, Alloc>::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
|
265
app/src/main/cpp/Dobby/external/TINYSTL/unordered_set.h
vendored
Normal file
265
app/src/main/cpp/Dobby/external/TINYSTL/unordered_set.h
vendored
Normal file
@ -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 <TINYSTL/allocator.h>
|
||||
#include <TINYSTL/buffer.h>
|
||||
#include <TINYSTL/hash.h>
|
||||
#include <TINYSTL/hash_base.h>
|
||||
|
||||
namespace tinystl {
|
||||
|
||||
template<typename Key, typename Alloc = TINYSTL_ALLOCATOR>
|
||||
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 unordered_hash_node<Key, void> > 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<iterator, bool> insert(const Key& key);
|
||||
pair<iterator, bool> 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<Key, void>* pointer;
|
||||
|
||||
size_t m_size;
|
||||
tinystl::buffer<pointer, Alloc> m_buckets;
|
||||
};
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline unordered_set<Key, Alloc>::unordered_set()
|
||||
: m_size(0)
|
||||
{
|
||||
buffer_init<pointer, Alloc>(&m_buckets);
|
||||
buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline unordered_set<Key, Alloc>::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<pointer, Alloc>(&m_buckets);
|
||||
buffer_resize<pointer, Alloc>(&m_buckets, nbuckets, 0);
|
||||
|
||||
for (pointer it = *other.m_buckets.first; it; it = it->next) {
|
||||
unordered_hash_node<Key, void>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, void>))) unordered_hash_node<Key, void>(*it);
|
||||
newnode->next = newnode->prev = 0;
|
||||
unordered_hash_node_insert(newnode, hash(it->first), m_buckets.first, nbuckets - 1);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline unordered_set<Key, Alloc>::unordered_set(unordered_set&& other)
|
||||
: m_size(other.m_size)
|
||||
{
|
||||
buffer_move(&m_buckets, &other.m_buckets);
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline unordered_set<Key, Alloc>::~unordered_set() {
|
||||
if (m_buckets.first != m_buckets.last)
|
||||
clear();
|
||||
buffer_destroy<pointer, Alloc>(&m_buckets);
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline unordered_set<Key, Alloc>& unordered_set<Key, Alloc>::operator=(const unordered_set<Key, Alloc>& other) {
|
||||
unordered_set<Key, Alloc>(other).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline unordered_set<Key, Alloc>& unordered_set<Key, Alloc>::operator=(unordered_set&& other) {
|
||||
unordered_set(static_cast<unordered_set&&>(other)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline typename unordered_set<Key, Alloc>::iterator unordered_set<Key, Alloc>::begin() const {
|
||||
iterator cit;
|
||||
cit.node = *m_buckets.first;
|
||||
return cit;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline typename unordered_set<Key, Alloc>::iterator unordered_set<Key, Alloc>::end() const {
|
||||
iterator cit;
|
||||
cit.node = 0;
|
||||
return cit;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline bool unordered_set<Key, Alloc>::empty() const {
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline size_t unordered_set<Key, Alloc>::size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline void unordered_set<Key, Alloc>::clear() {
|
||||
pointer it = *m_buckets.first;
|
||||
while (it) {
|
||||
const pointer next = it->next;
|
||||
it->~unordered_hash_node<Key, void>();
|
||||
Alloc::static_deallocate(it, sizeof(unordered_hash_node<Key, void>));
|
||||
|
||||
it = next;
|
||||
}
|
||||
|
||||
m_buckets.last = m_buckets.first;
|
||||
buffer_resize<pointer, Alloc>(&m_buckets, 9, 0);
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline typename unordered_set<Key, Alloc>::iterator unordered_set<Key, Alloc>::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<typename Key, typename Alloc>
|
||||
inline void unordered_set<Key, Alloc>::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<pointer, Alloc>(&m_buckets, newnbuckets + 1, 0);
|
||||
unordered_hash_node<Key, void>** 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<typename Key, typename Alloc>
|
||||
inline pair<typename unordered_set<Key, Alloc>::iterator, bool> unordered_set<Key, Alloc>::insert(const Key& key) {
|
||||
pair<iterator, bool> result;
|
||||
result.second = false;
|
||||
|
||||
result.first = find(key);
|
||||
if (result.first.node != 0)
|
||||
return result;
|
||||
|
||||
unordered_hash_node<Key, void>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, void>))) unordered_hash_node<Key, void>(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<typename Key, typename Alloc>
|
||||
inline pair<typename unordered_set<Key, Alloc>::iterator, bool> unordered_set<Key, Alloc>::emplace(Key&& key) {
|
||||
pair<iterator, bool> result;
|
||||
result.second = false;
|
||||
|
||||
result.first = find(key);
|
||||
if (result.first.node != 0)
|
||||
return result;
|
||||
|
||||
const size_t keyhash = hash(key);
|
||||
unordered_hash_node<Key, void>* newnode = new(placeholder(), Alloc::static_allocate(sizeof(unordered_hash_node<Key, void>))) unordered_hash_node<Key, void>(static_cast<Key&&>(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<typename Key, typename Alloc>
|
||||
inline void unordered_set<Key, Alloc>::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<Key, void>();
|
||||
Alloc::static_deallocate((void*)where.node, sizeof(unordered_hash_node<Key, void>));
|
||||
--m_size;
|
||||
}
|
||||
|
||||
template<typename Key, typename Alloc>
|
||||
inline size_t unordered_set<Key, Alloc>::erase(const Key& key) {
|
||||
const iterator it = find(key);
|
||||
if (it.node == 0)
|
||||
return 0;
|
||||
|
||||
erase(it);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename Key, typename Alloc>
|
||||
void unordered_set<Key, Alloc>::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
|
353
app/src/main/cpp/Dobby/external/TINYSTL/vector.h
vendored
Normal file
353
app/src/main/cpp/Dobby/external/TINYSTL/vector.h
vendored
Normal file
@ -0,0 +1,353 @@
|
||||
/*-
|
||||
* 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 <TINYSTL/allocator.h>
|
||||
#include <TINYSTL/buffer.h>
|
||||
#include <TINYSTL/new.h>
|
||||
#include <TINYSTL/stddef.h>
|
||||
|
||||
namespace tinystl {
|
||||
template <typename T, typename Alloc = TINYSTL_ALLOCATOR> class vector {
|
||||
using iterator = T *;
|
||||
|
||||
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 <typename Param> void emplace_back(const Param ¶m);
|
||||
|
||||
void shrink_to_fit();
|
||||
|
||||
void swap(vector &other);
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
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 <typename Param> void emplace(iterator where, const Param ¶m);
|
||||
|
||||
iterator erase(iterator where);
|
||||
iterator erase(iterator first, iterator last);
|
||||
|
||||
iterator erase_unordered(iterator where);
|
||||
iterator erase_unordered(iterator first, iterator last);
|
||||
|
||||
iterator find(const T &other) const;
|
||||
void sort(int (*compare)(const T &elem0, const T &elem1));
|
||||
void sort(unsigned begin, unsigned end, int (*compare)(const T &elem0, const T &elem1));
|
||||
|
||||
private:
|
||||
int partition(int (*compare)(const T &elem0, const T &elem1), int p, int r);
|
||||
void quick_sort(int (*compare)(const T &elem0, const T &elem1), int p, int r);
|
||||
|
||||
private:
|
||||
buffer<T, Alloc> m_buffer;
|
||||
};
|
||||
|
||||
template <typename T, typename Alloc> inline vector<T, Alloc>::vector() {
|
||||
buffer_init(&m_buffer);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline vector<T, Alloc>::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 <typename T, typename Alloc> inline vector<T, Alloc>::vector(vector &&other) {
|
||||
buffer_move(&m_buffer, &other.m_buffer);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline vector<T, Alloc>::vector(size_t size) {
|
||||
buffer_init(&m_buffer);
|
||||
buffer_resize(&m_buffer, size);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline vector<T, Alloc>::vector(size_t size, const T &value) {
|
||||
buffer_init(&m_buffer);
|
||||
buffer_resize(&m_buffer, size, value);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline vector<T, Alloc>::vector(const T *first, const T *last) {
|
||||
buffer_init(&m_buffer);
|
||||
buffer_insert(&m_buffer, m_buffer.last, first, last);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline vector<T, Alloc>::~vector() {
|
||||
buffer_destroy(&m_buffer);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline vector<T, Alloc> &vector<T, Alloc>::operator=(const vector &other) {
|
||||
vector(other).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> vector<T, Alloc> &vector<T, Alloc>::operator=(vector &&other) {
|
||||
buffer_destroy(&m_buffer);
|
||||
buffer_move(&m_buffer, &other.m_buffer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::assign(const T *first, const T *last) {
|
||||
buffer_clear(&m_buffer);
|
||||
buffer_insert(&m_buffer, m_buffer.last, first, last);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline const T *vector<T, Alloc>::data() const {
|
||||
return m_buffer.first;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline T *vector<T, Alloc>::data() {
|
||||
return m_buffer.first;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline size_t vector<T, Alloc>::size() const {
|
||||
return (size_t)(m_buffer.last - m_buffer.first);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline size_t vector<T, Alloc>::capacity() const {
|
||||
return (size_t)(m_buffer.capacity - m_buffer.first);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline bool vector<T, Alloc>::empty() const {
|
||||
return m_buffer.last == m_buffer.first;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline T &vector<T, Alloc>::operator[](size_t idx) {
|
||||
return m_buffer.first[idx];
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline const T &vector<T, Alloc>::operator[](size_t idx) const {
|
||||
return m_buffer.first[idx];
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline const T &vector<T, Alloc>::front() const {
|
||||
return m_buffer.first[0];
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline T &vector<T, Alloc>::front() {
|
||||
return m_buffer.first[0];
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline const T &vector<T, Alloc>::back() const {
|
||||
return m_buffer.last[-1];
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline T &vector<T, Alloc>::back() {
|
||||
return m_buffer.last[-1];
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::resize(size_t size) {
|
||||
buffer_resize(&m_buffer, size);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::resize(size_t size, const T &value) {
|
||||
buffer_resize(&m_buffer, size, value);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::clear() {
|
||||
buffer_clear(&m_buffer);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::reserve(size_t capacity) {
|
||||
buffer_reserve(&m_buffer, capacity);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::push_back(const T &t) {
|
||||
buffer_append(&m_buffer, &t);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::emplace_back() {
|
||||
buffer_append(&m_buffer);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
template <typename Param>
|
||||
inline void vector<T, Alloc>::emplace_back(const Param ¶m) {
|
||||
buffer_append(&m_buffer, ¶m);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::pop_back() {
|
||||
buffer_erase(&m_buffer, m_buffer.last - 1, m_buffer.last);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::shrink_to_fit() {
|
||||
buffer_shrink_to_fit(&m_buffer);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::swap(vector &other) {
|
||||
buffer_swap(&m_buffer, &other.m_buffer);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline typename vector<T, Alloc>::iterator vector<T, Alloc>::begin() {
|
||||
return m_buffer.first;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline typename vector<T, Alloc>::iterator vector<T, Alloc>::end() {
|
||||
return m_buffer.last;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline typename vector<T, Alloc>::const_iterator vector<T, Alloc>::begin() const {
|
||||
return m_buffer.first;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline typename vector<T, Alloc>::const_iterator vector<T, Alloc>::end() const {
|
||||
return m_buffer.last;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::insert(typename vector::iterator where) {
|
||||
buffer_insert(&m_buffer, where, 1);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc> inline void vector<T, Alloc>::insert(iterator where, const T &value) {
|
||||
buffer_insert(&m_buffer, where, &value, &value + 1);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline void vector<T, Alloc>::insert(iterator where, const T *first, const T *last) {
|
||||
buffer_insert(&m_buffer, where, first, last);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::erase(iterator where) {
|
||||
return buffer_erase(&m_buffer, where, where + 1);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::erase(iterator first, iterator last) {
|
||||
return buffer_erase(&m_buffer, first, last);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::erase_unordered(iterator where) {
|
||||
return buffer_erase_unordered(&m_buffer, where, where + 1);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::erase_unordered(iterator first, iterator last) {
|
||||
return buffer_erase_unordered(&m_buffer, first, last);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
template <typename Param>
|
||||
void vector<T, Alloc>::emplace(typename vector::iterator where, const Param ¶m) {
|
||||
buffer_insert(&m_buffer, where, ¶m, ¶m + 1);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::find(const T &other) const {
|
||||
for (unsigned i = 0; i < size(); ++i)
|
||||
if (m_buffer.first[i] == other)
|
||||
return &m_buffer.first[i];
|
||||
|
||||
return m_buffer.last;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline int vector<T, Alloc>::partition(int (*compare)(const T &elem0, const T &elem1), int p, int r) {
|
||||
T tmp, pivot = m_buffer.first[p];
|
||||
int left = p;
|
||||
|
||||
for (int i = p + 1; i <= r; i++) {
|
||||
if (compare(m_buffer.first[i], pivot) < 0) {
|
||||
left++;
|
||||
tmp = m_buffer.first[i];
|
||||
m_buffer.first[i] = m_buffer.first[left];
|
||||
m_buffer.first[left] = tmp;
|
||||
}
|
||||
}
|
||||
tmp = m_buffer.first[p];
|
||||
m_buffer.first[p] = m_buffer.first[left];
|
||||
m_buffer.first[left] = tmp;
|
||||
return left;
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline void vector<T, Alloc>::quick_sort(int (*compare)(const T &elem0, const T &elem1), int p, int r) {
|
||||
if (p < r) {
|
||||
int q = partition(compare, p, r);
|
||||
quick_sort(compare, p, q - 1);
|
||||
quick_sort(compare, q + 1, r);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline void vector<T, Alloc>::sort(int (*compare)(const T &elem0, const T &elem1)) {
|
||||
quick_sort(compare, 0, (int)size() - 1);
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc>
|
||||
inline void vector<T, Alloc>::sort(unsigned begin, unsigned end, int (*compare)(const T &elem0, const T &elem1)) {
|
||||
quick_sort(compare, (int)begin, (int)end);
|
||||
}
|
||||
} // namespace tinystl
|
||||
|
||||
#endif // TINYSTL_VECTOR_H
|
18
app/src/main/cpp/Dobby/external/deprecated/misc-helper/CMakeLists.txt
vendored
Normal file
18
app/src/main/cpp/Dobby/external/deprecated/misc-helper/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
include_directories(.)
|
||||
|
||||
if(NOT DOBBY_BUILD_KERNEL_MODE)
|
||||
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}
|
||||
)
|
65
app/src/main/cpp/Dobby/external/deprecated/misc-helper/async_logger.cc
vendored
Normal file
65
app/src/main/cpp/Dobby/external/deprecated/misc-helper/async_logger.cc
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#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);
|
||||
}
|
129
app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.cc
vendored
Normal file
129
app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.cc
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
#include "pthread_helper.h"
|
||||
#include <stdio.h>
|
||||
#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
|
85
app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.h
vendored
Normal file
85
app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/pthread_helper.h
vendored
Normal file
@ -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 <windows.h>
|
||||
#include <process.h>
|
||||
#include <errno.h>
|
||||
|
||||
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 <pthread.h>
|
||||
#include <unistd.h>
|
||||
#define Sleep(num) usleep(num * 1000)
|
||||
#endif
|
||||
|
||||
#endif /* CROSS_THREAD_H */
|
30
app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/unistd_helper.h
vendored
Normal file
30
app/src/main/cpp/Dobby/external/deprecated/misc-helper/deprecated/unistd_helper.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <io.h>
|
||||
#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 <sys/types.h> */
|
||||
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 <unistd.h>
|
||||
|
||||
#endif
|
11
app/src/main/cpp/Dobby/external/deprecated/misc-helper/format_printer.cc
vendored
Normal file
11
app/src/main/cpp/Dobby/external/deprecated/misc-helper/format_printer.cc
vendored
Normal file
@ -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))
|
||||
LOG_FUNCTION_IMPL(0, "\n");
|
||||
LOG_FUNCTION_IMPL(0, "%02X ", bytes[ix]);
|
||||
}
|
||||
LOG_FUNCTION_IMPL(0, "\n");
|
||||
}
|
8
app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/async_logger.h
vendored
Normal file
8
app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/async_logger.h
vendored
Normal file
@ -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
|
3
app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/format_printer.h
vendored
Normal file
3
app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/format_printer.h
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
#include "dobby/common.h"
|
||||
|
||||
void hexdump(const uint8_t *bytes, size_t len);
|
17
app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/variable_cache.h
vendored
Normal file
17
app/src/main/cpp/Dobby/external/deprecated/misc-helper/misc-helper/variable_cache.h
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef VARIABLE_CACHE_H
|
||||
#define VARIABLE_CACHE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
118
app/src/main/cpp/Dobby/external/deprecated/misc-helper/variable_cache.c
vendored
Normal file
118
app/src/main/cpp/Dobby/external/deprecated/misc-helper/variable_cache.c
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
#include "misc-helper/variable_cache.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "deprecated/unistd_helper.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
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;
|
||||
}
|
18
app/src/main/cpp/Dobby/external/logging/CMakeLists.txt
vendored
Normal file
18
app/src/main/cpp/Dobby/external/logging/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
include_directories(.)
|
||||
|
||||
set(SOURCE_FILE_LIST
|
||||
logging.cc
|
||||
)
|
||||
|
||||
if (DOBBY_BUILD_KERNEL_MODE)
|
||||
set(SOURCE_FILE_LIST
|
||||
logging_kern.cc
|
||||
)
|
||||
endif ()
|
||||
|
||||
get_absolute_path_list(SOURCE_FILE_LIST SOURCE_FILE_LIST_)
|
||||
set(SOURCE_FILE_LIST ${SOURCE_FILE_LIST_})
|
||||
|
||||
add_library(logging
|
||||
${SOURCE_FILE_LIST}
|
||||
)
|
137
app/src/main/cpp/Dobby/external/logging/logging.cc
vendored
Normal file
137
app/src/main/cpp/Dobby/external/logging/logging.cc
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
#include "logging/logging.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include "./priv_headers/_simple.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define PUBLIC
|
||||
#else
|
||||
#define PUBLIC __attribute__((visibility("default")))
|
||||
#define INTERNAL __attribute__((visibility("internal")))
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wformat"
|
||||
|
||||
Logger *Logger::g_logger = nullptr;
|
||||
|
||||
void Logger::logv(LogLevel level, const char *_fmt, va_list ap) {
|
||||
if (level < log_level_)
|
||||
return;
|
||||
|
||||
char fmt_buffer[4096] = {0};
|
||||
|
||||
if (log_tag_ != nullptr) {
|
||||
snprintf(fmt_buffer + strlen(fmt_buffer), sizeof(fmt_buffer) - strlen(fmt_buffer), "%s ", log_tag_);
|
||||
}
|
||||
|
||||
if (enable_time_tag_) {
|
||||
time_t now = time(NULL);
|
||||
struct tm *tm = localtime(&now);
|
||||
snprintf(fmt_buffer + strlen(fmt_buffer), sizeof(fmt_buffer) - strlen(fmt_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(fmt_buffer + strlen(fmt_buffer), sizeof(fmt_buffer) - strlen(fmt_buffer), "%s\n", _fmt);
|
||||
|
||||
if (enable_syslog_) {
|
||||
#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_buffer, ap, (void *)&os_log_with_args);
|
||||
vsyslog(LOG_ALERT, fmt_buffer, ap);
|
||||
|
||||
static int _logDescriptor = 0;
|
||||
if (_logDescriptor == 0) {
|
||||
_logDescriptor = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (_logDescriptor != -1) {
|
||||
fcntl(_logDescriptor, F_SETFD, FD_CLOEXEC);
|
||||
struct sockaddr_un addr;
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, _PATH_LOG, sizeof(addr.sun_path));
|
||||
if (connect(_logDescriptor, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
close(_logDescriptor);
|
||||
_logDescriptor = -1;
|
||||
ERROR_LOG("Failed to connect to syslogd: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_logDescriptor > 0) {
|
||||
vdprintf(_logDescriptor, fmt_buffer, ap);
|
||||
}
|
||||
#elif defined(_POSIX_VERSION)
|
||||
vsyslog(LOG_ERR, fmt_buffer, ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (log_file_ != nullptr) {
|
||||
char buffer[0x4000] = {0};
|
||||
vsnprintf(buffer, sizeof(buffer) - 1, fmt_buffer, ap);
|
||||
#if defined(USER_CXX_FILESTREAM)
|
||||
log_file_stream_->write(buffer, strlen(buffer));
|
||||
log_file_stream_->flush();
|
||||
#else
|
||||
fwrite(buffer, strlen(buffer), 1, log_file_stream_);
|
||||
fflush(log_file_stream_);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (1 || !enable_syslog_ && log_file_ == nullptr) {
|
||||
#if defined(__ANDROID__)
|
||||
__android_log_vprint(ANDROID_LOG_INFO, NULL, fmt_buffer, ap);
|
||||
#else
|
||||
vprintf(fmt_buffer, ap);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang diagnostic warning "-Wformat"
|
||||
|
||||
void *logger_create(const char *tag, const char *file, LogLevel level, bool enable_time_tag, bool enable_syslog) {
|
||||
Logger *logger = new Logger(tag, file, level, enable_time_tag, enable_syslog);
|
||||
return logger;
|
||||
}
|
||||
|
||||
void logger_set_options(void *logger, const char *tag, const char *file, LogLevel level, bool enable_time_tag,
|
||||
bool enable_syslog) {
|
||||
if (logger == nullptr) {
|
||||
logger = Logger::Shared();
|
||||
}
|
||||
((Logger *)logger)->setOptions(tag, file, level, enable_time_tag, enable_syslog);
|
||||
}
|
||||
|
||||
void logger_log_impl(void *logger, LogLevel level, const char *fmt, ...) {
|
||||
if (logger == nullptr) {
|
||||
logger = Logger::Shared();
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
((Logger *)logger)->logv(level, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
87
app/src/main/cpp/Dobby/external/logging/logging/check_logging.h
vendored
Normal file
87
app/src/main/cpp/Dobby/external/logging/logging/check_logging.h
vendored
Normal file
@ -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_LOG("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_LOG("%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_LOG(" Check failed: %s.\n", #lhs " " #op " " #rhs); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DCHECK_OP(name, op, lhs, rhs) \
|
||||
do { \
|
||||
if (!((lhs)op(rhs))) { \
|
||||
FATAL_LOG("%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
|
202
app/src/main/cpp/Dobby/external/logging/logging/logging.h
vendored
Normal file
202
app/src/main/cpp/Dobby/external/logging/logging/logging.h
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define LOG_TAG NULL
|
||||
|
||||
typedef enum {
|
||||
LOG_LEVEL_DEBUG = 0,
|
||||
LOG_LEVEL_INFO = 1,
|
||||
LOG_LEVEL_WARN = 2,
|
||||
LOG_LEVEL_ERROR = 3,
|
||||
LOG_LEVEL_FATAL = 4
|
||||
} LogLevel;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#if defined(USE_CXX_FILESTREAM)
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
LogLevel log_level_;
|
||||
|
||||
const char *log_tag_;
|
||||
|
||||
const char *log_file_;
|
||||
#if defined(USE_CXX_FILESTREAM)
|
||||
std::fstream *log_file_stream_;
|
||||
#else
|
||||
FILE *log_file_stream_;
|
||||
#endif
|
||||
|
||||
bool enable_time_tag_;
|
||||
bool enable_syslog_;
|
||||
|
||||
static Logger *g_logger;
|
||||
static Logger *Shared() {
|
||||
if (g_logger == nullptr) {
|
||||
g_logger = new Logger();
|
||||
}
|
||||
return g_logger;
|
||||
}
|
||||
|
||||
Logger() {
|
||||
log_tag_ = nullptr;
|
||||
log_file_ = nullptr;
|
||||
log_level_ = LOG_LEVEL_DEBUG;
|
||||
enable_time_tag_ = false;
|
||||
enable_syslog_ = false;
|
||||
}
|
||||
|
||||
Logger(const char *tag, const char *file, LogLevel level, bool enable_time_tag, bool enable_syslog) {
|
||||
setTag(tag);
|
||||
setLogFile(file);
|
||||
setLogLevel(level);
|
||||
enable_time_tag_ = enable_time_tag;
|
||||
enable_syslog_ = enable_syslog;
|
||||
}
|
||||
|
||||
void setOptions(const char *tag, const char *file, LogLevel level, bool enable_time_tag, bool enable_syslog) {
|
||||
if (tag)
|
||||
setTag(tag);
|
||||
if (file)
|
||||
setLogFile(file);
|
||||
setLogLevel(level);
|
||||
enable_time_tag_ = enable_time_tag;
|
||||
enable_syslog_ = enable_syslog;
|
||||
}
|
||||
|
||||
void setTag(const char *tag) {
|
||||
log_tag_ = tag;
|
||||
}
|
||||
|
||||
void setLogFile(const char *file) {
|
||||
log_file_ = file;
|
||||
#if defined(USE_CXX_FILESTREAM)
|
||||
log_file_stream_ = new std::fstream();
|
||||
log_file_stream_->open(log_file_, std::ios::out | std::ios::app);
|
||||
#else
|
||||
log_file_stream_ = fopen(log_file_, "a");
|
||||
#endif
|
||||
}
|
||||
|
||||
void setLogLevel(LogLevel level) {
|
||||
log_level_ = level;
|
||||
}
|
||||
|
||||
void enableTimeTag() {
|
||||
enable_time_tag_ = true;
|
||||
}
|
||||
|
||||
void enableSyslog() {
|
||||
enable_syslog_ = true;
|
||||
}
|
||||
|
||||
void logv(LogLevel level, const char *fmt, va_list ap);
|
||||
|
||||
void log(LogLevel level, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logv(level, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void debug(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logv(LOG_LEVEL_DEBUG, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void info(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logv(LOG_LEVEL_INFO, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void warn(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logv(LOG_LEVEL_WARN, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void error(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logv(LOG_LEVEL_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void fatal(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logv(LOG_LEVEL_FATAL, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(DOBBY_LOGGING_DISABLE)
|
||||
#define LOG_FUNCTION_IMPL(...)
|
||||
#else
|
||||
#if !defined(LOG_FUNCTION_IMPL)
|
||||
#define LOG_FUNCTION_IMPL logger_log_impl
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void *logger_create(const char *tag, const char *file, LogLevel level, bool enable_time_tag, bool enable_syslog);
|
||||
void logger_set_options(void *logger, const char *tag, const char *file, LogLevel level, bool enable_time_tag,
|
||||
bool enable_syslog);
|
||||
void logger_log_impl(void *logger, LogLevel level, const char *fmt, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define LOG(level, fmt, ...) \
|
||||
do { \
|
||||
if (LOG_TAG) \
|
||||
LOG_FUNCTION_IMPL(NULL, level, "[%s] " fmt, LOG_TAG, ##__VA_ARGS__); \
|
||||
else \
|
||||
LOG_FUNCTION_IMPL(NULL, level, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_LOG(fmt, ...) \
|
||||
do { \
|
||||
LOG(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define INFO_LOG(fmt, ...) \
|
||||
do { \
|
||||
LOG(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define WARN_LOG(fmt, ...) \
|
||||
do { \
|
||||
LOG(LOG_LEVEL_WARN, 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_LOG(fmt, ...) \
|
||||
do { \
|
||||
LOG(LOG_LEVEL_FATAL, "[!] [%s:%d:%s]" fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define UNIMPLEMENTED() FATAL_LOG("%s\n", "unimplemented code!!!")
|
||||
#define UNREACHABLE() FATAL_LOG("%s\n", "unreachable code!!!")
|
0
app/src/main/cpp/Dobby/external/logging/logging_kern.cc
vendored
Normal file
0
app/src/main/cpp/Dobby/external/logging/logging_kern.cc
vendored
Normal file
162
app/src/main/cpp/Dobby/external/logging/priv_headers/_simple.h
vendored
Normal file
162
app/src/main/cpp/Dobby/external/logging/priv_headers/_simple.h
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2010, 2013 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 _SYSTEM_SIMPLE_H_
|
||||
#define _SYSTEM_SIMPLE_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <Availability.h>
|
||||
|
||||
typedef void *_SIMPLE_STRING;
|
||||
typedef const char *_esc_func(unsigned char);
|
||||
|
||||
__BEGIN_DECLS
|
||||
/*
|
||||
* A simplified vfprintf variant. The format string is interpreted with
|
||||
* arguments from the va_list, and the results are written to the given
|
||||
* file descriptor.
|
||||
*/
|
||||
void _simple_vdprintf(int __fd, const char *__fmt, va_list __ap) __printflike(2, 0);
|
||||
|
||||
/*
|
||||
* A simplified fprintf variant. The format string is interpreted with
|
||||
* arguments from the variable argument list, and the results are written
|
||||
* to the given file descriptor.
|
||||
*/
|
||||
void _simple_dprintf(int __fd, const char *__fmt, ...) __printflike(2, 3);
|
||||
|
||||
/*
|
||||
* A simplified string allocate routine. Pass the opaque pointer to structure
|
||||
* to _simple_*sprintf() routines. Use _simple_string() to retrieve the
|
||||
* current string (the string is guaranteed to be null terminated only on
|
||||
* the call to _simple_string()). Use _simple_sfree() to free the structure
|
||||
* and string memory.
|
||||
*/
|
||||
_SIMPLE_STRING _simple_salloc(void);
|
||||
|
||||
/*
|
||||
* The format string is interpreted with arguments from the va_list, and the
|
||||
* results are appended to the string maintained by the opaque structure, as
|
||||
* returned by a previous call to _simple_salloc(). Non-zero is returned on
|
||||
* out-of-memory error.
|
||||
*/
|
||||
int _simple_vsprintf(_SIMPLE_STRING __b, const char *__fmt, va_list __ap) __printflike(2, 0);
|
||||
|
||||
/*
|
||||
* The format string is interpreted with arguments from the variable argument
|
||||
* list, and the results are appended to the string maintained by the opaque
|
||||
* structure, as returned by a previous call to _simple_salloc(). Non-zero is
|
||||
* returned on out-of-memory error.
|
||||
*/
|
||||
int _simple_sprintf(_SIMPLE_STRING __b, const char *__fmt, ...) __printflike(2, 3);
|
||||
|
||||
/*
|
||||
* Like _simple_vsprintf(), except __esc is a function to call on each
|
||||
* character; the function returns NULL if the character should be passed
|
||||
* as is, otherwise, the returned character string is used instead.
|
||||
*/
|
||||
int _simple_vesprintf(_SIMPLE_STRING __b, _esc_func __esc, const char *__fmt, va_list __ap) __printflike(3, 0);
|
||||
|
||||
/*
|
||||
* Like _simple_sprintf(), except __esc is a function to call on each
|
||||
* character; the function returns NULL if the character should be passed
|
||||
* as is, otherwise, the returned character string is used instead.
|
||||
*/
|
||||
int _simple_esprintf(_SIMPLE_STRING __b, _esc_func __esc, const char *__fmt, ...) __printflike(3, 4);
|
||||
|
||||
/*
|
||||
* Return the null terminated string from the opaque structure, as returned
|
||||
* by a previous call to _simple_salloc().
|
||||
*/
|
||||
char *_simple_string(_SIMPLE_STRING __b);
|
||||
|
||||
/*
|
||||
* Reposition the pointer to the first null in the buffer. After a call to
|
||||
* _simple_string, the buffer can be modified, and shrunk.
|
||||
*/
|
||||
void _simple_sresize(_SIMPLE_STRING __b);
|
||||
|
||||
/*
|
||||
* Append the null-terminated string to the string associated with the opaque
|
||||
* structure. Non-zero is returned on out-of-memory error.
|
||||
*/
|
||||
int _simple_sappend(_SIMPLE_STRING __b, const char *__str);
|
||||
|
||||
/*
|
||||
* Like _simple_sappend(), except __esc is a function to call on each
|
||||
* character; the function returns NULL if the character should be passed
|
||||
* as is, otherwise, the returned character string is used instead.
|
||||
*/
|
||||
int _simple_esappend(_SIMPLE_STRING __b, _esc_func __esc, const char *__str);
|
||||
|
||||
/*
|
||||
* Write the string associated with the opaque structure to the file descriptor.
|
||||
*/
|
||||
void _simple_put(_SIMPLE_STRING __b, int __fd);
|
||||
|
||||
/*
|
||||
* Write the string associated with the opaque structure and a trailing newline,
|
||||
* to the file descriptor.
|
||||
*/
|
||||
void _simple_putline(_SIMPLE_STRING __b, int __fd);
|
||||
|
||||
/*
|
||||
* Free the opaque structure, and the associated string.
|
||||
*/
|
||||
void _simple_sfree(_SIMPLE_STRING __b);
|
||||
|
||||
/*
|
||||
* Simplified ASL log interface; does not use malloc. Unfortunately, this
|
||||
* requires knowledge of the format used by ASL.
|
||||
*/
|
||||
#ifndef ASL_LEVEL_DEBUG
|
||||
#define ASL_LEVEL_EMERG 0
|
||||
#define ASL_LEVEL_ALERT 1
|
||||
#define ASL_LEVEL_CRIT 2
|
||||
#define ASL_LEVEL_ERR 3
|
||||
#define ASL_LEVEL_WARNING 4
|
||||
#define ASL_LEVEL_NOTICE 5
|
||||
#define ASL_LEVEL_INFO 6
|
||||
#define ASL_LEVEL_DEBUG 7
|
||||
#endif
|
||||
|
||||
void _simple_asl_log(int __level, const char *__facility, const char *__message);
|
||||
void _simple_asl_log_prog(int level, const char *facility, const char *message, const char *progname);
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0)
|
||||
_SIMPLE_STRING _simple_asl_msg_new(void);
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0)
|
||||
void _simple_asl_msg_set(_SIMPLE_STRING __b, const char *__key, const char *__val);
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0)
|
||||
void _simple_asl_send(_SIMPLE_STRING __b);
|
||||
|
||||
__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0)
|
||||
const char *_simple_getenv(const char *envp[], const char *var);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _SYSTEM_SIMPLE_H_ */
|
3
app/src/main/cpp/Dobby/external/osbase/CMakeLists.txt
vendored
Normal file
3
app/src/main/cpp/Dobby/external/osbase/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
add_library(osbase STATIC
|
||||
${PROJECT_SOURCE_DIR}/source/Backend/UserMode/UnifiedInterface/platform-posix.cc
|
||||
)
|
152
app/src/main/cpp/Dobby/include/dobby.h
Normal file
152
app/src/main/cpp/Dobby/include/dobby.h
Normal file
@ -0,0 +1,152 @@
|
||||
#ifndef dobby_h
|
||||
#define dobby_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
10
app/src/main/cpp/Dobby/scripts/Dockerfile
Normal file
10
app/src/main/cpp/Dobby/scripts/Dockerfile
Normal file
@ -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
|
242
app/src/main/cpp/Dobby/scripts/platform_builder.py
Normal file
242
app/src/main/cpp/Dobby/scripts/platform_builder.py
Normal file
@ -0,0 +1,242 @@
|
||||
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 = ""
|
||||
|
||||
shared_output_name = ""
|
||||
static_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":
|
||||
pass
|
||||
# self.cmake_args += ["-DDOBBY_GENERATE_SHARED=ON"]
|
||||
elif self.library_build_type == "static":
|
||||
pass
|
||||
# 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("cmake --build . --clean-first --target dobby --target dobby_static -- -j8", cwd=self.cmake_build_dir, shell=True, check=True)
|
||||
|
||||
os.system(f"mkdir -p {self.output_dir}")
|
||||
os.system(f"cp {self.cmake_build_dir}/{self.shared_output_name} {self.output_dir}")
|
||||
os.system(f"cp {self.cmake_build_dir}/{self.static_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)
|
||||
|
||||
self.shared_output_name = "libdobby.so"
|
||||
self.static_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)
|
||||
|
||||
self.shared_output_name = "libdobby.so"
|
||||
self.static_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"]
|
||||
|
||||
self.shared_output_name = "libdobby.dylib"
|
||||
self.static_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)
|
||||
|
||||
fat_output_dir = f"{project_dir}/build/{platform}/universal"
|
||||
subprocess.run(["mkdir", "-p", "{}".format(fat_output_dir)], check=True)
|
||||
cmd = ["lipo", "-create"] + files + ["-output", f"{fat_output_dir}/{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))
|
||||
|
||||
builder: PlatformBuilder = None
|
||||
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":
|
||||
DarwinPlatformBuilder.lipo_create_fat(project_dir, platform, builder.shared_output_name)
|
||||
DarwinPlatformBuilder.lipo_create_fat(project_dir, platform, builder.static_output_name)
|
61
app/src/main/cpp/Dobby/scripts/setup_linux_cross_compile.sh
Normal file
61
app/src/main/cpp/Dobby/scripts/setup_linux_cross_compile.sh
Normal file
@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
set -e
|
||||
|
||||
# sudo dpkg --add-architecture armhf
|
||||
# sudo dpkg --add-architecture i386
|
||||
# sudo dpkg --add-architecture arm64
|
||||
# sudo apt-get -y update
|
||||
# sudo apt-get -y dist-upgrade
|
||||
# sudo apt-get -y install git build-essential libssl-dev pkg-config unzip gcc-multilib
|
||||
# sudo apt-get -y install libc6-armhf-cross libc6-dev-armhf-cross gcc-arm-linux-gnueabihf libssl-dev:armhf
|
||||
# sudo apt-get -y install libc6-i386-cross libc6-dev-i386-cross gcc-i686-linux-gnu libssl-dev:i386
|
||||
# sudo apt-get -y install libc6-arm64-cross libc6-dev-arm64-cross gcc-aarch64-linux-gnu libssl-dev:arm64
|
||||
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install aptitude
|
||||
sudo apt-get -f -y install \
|
||||
apt-utils \
|
||||
binutils \
|
||||
build-essential \
|
||||
curl \
|
||||
wget \
|
||||
unzip \
|
||||
gcc-multilib \
|
||||
g++-multilib \
|
||||
make \
|
||||
zsh
|
||||
|
||||
sudo apt-get -f -y install gcc g++ libc6-dev
|
||||
sudo apt-get -f -y install gcc-i686-linux-gnu g++-i686-linux-gnu
|
||||
sudo apt-get -f -y install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
|
||||
sudo apt-get -f -y install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
|
||||
|
||||
mkdir -p ~/opt
|
||||
|
||||
cd ~/opt
|
||||
CMAKE_VERSION=3.25.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=15.0.6
|
||||
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
|
22
app/src/main/cpp/Dobby/scripts/setup_macos_cross_compile.sh
Normal file
22
app/src/main/cpp/Dobby/scripts/setup_macos_cross_compile.sh
Normal file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
set -e
|
||||
|
||||
mkdir -p ~/opt
|
||||
|
||||
cd ~/opt
|
||||
CMAKE_VERSION=3.25.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=15.0.6
|
||||
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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user