├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── control ├── dependencies ├── include │ ├── capstone │ │ ├── arm.h │ │ ├── arm64.h │ │ ├── capstone.h │ │ ├── evm.h │ │ ├── m680x.h │ │ ├── m68k.h │ │ ├── mips.h │ │ ├── mos65xx.h │ │ ├── platform.h │ │ ├── ppc.h │ │ ├── sparc.h │ │ ├── systemz.h │ │ ├── tms320c64x.h │ │ ├── x86.h │ │ └── xcore.h │ ├── json-c │ │ ├── arraylist.h │ │ ├── debug.h │ │ ├── json_c_version.h │ │ ├── json_config.h │ │ ├── json_inttypes.h │ │ ├── json_object.h │ │ ├── json_object_iterator.h │ │ ├── json_object_private.h │ │ ├── json_patch.h │ │ ├── json_pointer.h │ │ ├── json_pointer_private.h │ │ ├── json_tokener.h │ │ ├── json_types.h │ │ ├── json_util.h │ │ ├── json_visit.h │ │ ├── linkhash.h │ │ ├── math_compat.h │ │ ├── printbuf.h │ │ ├── random_seed.h │ │ ├── snprintf_compat.h │ │ ├── strdup_compat.h │ │ ├── strerror_override.h │ │ └── vasprintf_compat.h │ ├── ncurses.h │ └── ncursesw │ │ ├── curses.h │ │ ├── cursesapp.h │ │ ├── cursesf.h │ │ ├── cursesm.h │ │ ├── cursesp.h │ │ ├── cursesw.h │ │ ├── cursslk.h │ │ ├── eti.h │ │ ├── etip.h │ │ ├── form.h │ │ ├── menu.h │ │ ├── nc_tparm.h │ │ ├── ncurses.h │ │ ├── ncurses_dll.h │ │ ├── panel.h │ │ ├── term.h │ │ ├── term_entry.h │ │ ├── termcap.h │ │ ├── tic.h │ │ └── unctrl.h ├── kat │ ├── hashtable.c │ ├── hashtable.h │ ├── highlight.c │ └── highlight.h └── libs │ ├── libcapstone-ios.a │ ├── libcapstone-mac.a │ ├── libjson-c-ios.a │ ├── libjson-c-mac.a │ └── libncursesw-ios.a ├── deploy_to_device.py ├── imgs ├── TRACER_ARG_FORMAT_DESCRIPTIVE.png ├── TRACER_ARG_FORMAT_EXCLUDE.png ├── banner.gif ├── thread-output-interweaving.png └── tui.png ├── layout └── usr │ └── lib │ └── libobjsee.dylib ├── objsee.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── src ├── libobjsee │ ├── Resources │ │ └── Info.plist │ ├── config │ │ ├── config_decode.c │ │ ├── config_decode.h │ │ ├── config_encode.c │ │ └── config_encode.h │ ├── formatting │ │ ├── color_utils.c │ │ ├── color_utils.h │ │ ├── format.c │ │ └── format.h │ ├── injection │ │ └── loader.m │ ├── interception │ │ ├── arguments │ │ │ ├── arg_capture.c │ │ │ ├── arg_capture.h │ │ │ ├── arg_description.c │ │ │ ├── arg_description.h │ │ │ ├── objc_arg_description.c │ │ │ ├── objc_arg_description.h │ │ │ ├── realized_class_tracking.c │ │ │ └── realized_class_tracking.h │ │ ├── msgSend_hook.c │ │ ├── msgSend_hook.h │ │ ├── rebind.c │ │ ├── rebind.h │ │ ├── selector_deny_list.c │ │ └── selector_deny_list.h │ ├── tracing │ │ ├── objc-internal.h │ │ ├── signal_guard.h │ │ ├── tracer.c │ │ ├── tracer.h │ │ ├── tracer_core.c │ │ ├── tracer_internal.h │ │ └── tracer_types.h │ ├── transport │ │ ├── event_handler.c │ │ ├── event_handler.h │ │ ├── transport.c │ │ └── transport.h │ └── type_decoding │ │ ├── blocks.c │ │ ├── blocks.h │ │ ├── encoding_description.c │ │ ├── encoding_description.h │ │ ├── encoding_size.c │ │ └── encoding_size.h ├── libobjseeTests │ ├── ArgDescriptionTests.m │ ├── BlockDescriptionTests.m │ ├── CoreSymbolicationTests.m │ ├── ObjcDescriptionTests.m │ ├── RealizedClassTrackingTests.m │ ├── SelectorDenyListTests.m │ ├── StructDecoderTests.m │ ├── TypeEncodingTests.m │ └── libobjseeTests.xctestplan └── objsee-cli │ ├── Makefile │ ├── app_launching.h │ ├── app_launching.m │ ├── cli_args.h │ ├── cli_args.m │ ├── exception_handling │ ├── crash_handler.h │ ├── crash_handler.m │ ├── mach_excServer.c │ ├── mach_excServer.h │ ├── symbolication.c │ └── symbolication.h │ ├── injector │ ├── dylib_injector.h │ └── dylib_injector.m │ ├── main.m │ ├── objsee-entitlements.xml │ ├── simulator │ ├── sim_launching.h │ ├── sim_launching.m │ ├── tmpfs_overlay.h │ └── tmpfs_overlay.m │ ├── trace_server.c │ ├── trace_server.h │ └── tui │ ├── tui_trace_server.c │ └── tui_trace_server.h └── testapp ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets ├── AccentColor.colorset │ └── Contents.json ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist ├── SceneDelegate.h ├── SceneDelegate.m ├── ViewController.h ├── ViewController.m └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | *.xcodeproj/xcshareddata 2 | *.xcodeproj/xcuserdata/ethanarbuckle.xcuserdatad/xcschemes/xcschememanagement.plist 3 | *.xcodeproj/xcuserdata 4 | .theos/ 5 | xcuserdata 6 | /packages 7 | /.vscode 8 | .stamp 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export PACKAGE_VERSION := 0.0.2 2 | 3 | ARCHS := arm64 4 | TARGET := iphone:clang:latest:16.1 5 | 6 | include $(THEOS)/makefiles/common.mk 7 | 8 | INCLUDE_DIRS := $(shell find . ./src/libobjsee -type d) 9 | INCLUDE_FLAGS := $(INCLUDE_DIRS:%=-I%) 10 | 11 | FRAMEWORK_NAME = objsee 12 | objsee_INSTALL_PATH = /Library/Frameworks 13 | objsee_FILES += $(shell find src/libobjsee -type f \( -name '*.c' -o -name '*.m' \)) 14 | objsee_PUBLIC_HEADERS += src/libobjsee/tracing/tracer.h src/libobjsee/tracing/tracer_types.h src/libobjsee/tracing/tracer_internal.h 15 | objsee_CFLAGS += -fobjc-arc $(INCLUDE_FLAGS) 16 | objsee_CFLAGS += -I./dependencies/include 17 | objsee_CFLAGS += -DOBJSEE_LIB_VERSION=\"$(PACKAGE_VERSION)\" 18 | objsee_LDFLAGS += -L./dependencies/libs/ 19 | objsee_LDFLAGS += -ljson-c-ios 20 | objsee_RESOURCE_DIRS += ./src/libobjsee/Resources 21 | msgSend_hook.c_CFLAGS += -fno-objc-arc 22 | msgSend_hook.c_CFLAGS += -O2 23 | include $(THEOS_MAKE_PATH)/framework.mk 24 | 25 | SUBPROJECTS += ./src/objsee-cli 26 | include $(THEOS_MAKE_PATH)/aggregate.mk -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.ethanarbuckle.objsee-framework 2 | Name: objsee 3 | Version: 0.0.1 4 | Architecture: iphoneos-arm 5 | Depends: firmware (>= 16.1) 6 | Description: objc_msgSend tracing framework 7 | Maintainer: Ethan Arbuckle 8 | Author: Ethan Arbuckle 9 | Section: System 10 | Tag: role::developer 11 | -------------------------------------------------------------------------------- /dependencies/include/capstone/evm.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPSTONE_EVM_H 2 | #define CAPSTONE_EVM_H 3 | 4 | /* Capstone Disassembly Engine */ 5 | /* By Nguyen Anh Quynh , 2013-2018 */ 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #include "platform.h" 12 | 13 | #ifdef _MSC_VER 14 | #pragma warning(disable:4201) 15 | #endif 16 | 17 | /// Instruction structure 18 | typedef struct cs_evm { 19 | unsigned char pop; ///< number of items popped from the stack 20 | unsigned char push; ///< number of items pushed into the stack 21 | unsigned int fee; ///< gas fee for the instruction 22 | } cs_evm; 23 | 24 | /// EVM instruction 25 | typedef enum evm_insn { 26 | EVM_INS_STOP = 0, 27 | EVM_INS_ADD = 1, 28 | EVM_INS_MUL = 2, 29 | EVM_INS_SUB = 3, 30 | EVM_INS_DIV = 4, 31 | EVM_INS_SDIV = 5, 32 | EVM_INS_MOD = 6, 33 | EVM_INS_SMOD = 7, 34 | EVM_INS_ADDMOD = 8, 35 | EVM_INS_MULMOD = 9, 36 | EVM_INS_EXP = 10, 37 | EVM_INS_SIGNEXTEND = 11, 38 | EVM_INS_LT = 16, 39 | EVM_INS_GT = 17, 40 | EVM_INS_SLT = 18, 41 | EVM_INS_SGT = 19, 42 | EVM_INS_EQ = 20, 43 | EVM_INS_ISZERO = 21, 44 | EVM_INS_AND = 22, 45 | EVM_INS_OR = 23, 46 | EVM_INS_XOR = 24, 47 | EVM_INS_NOT = 25, 48 | EVM_INS_BYTE = 26, 49 | EVM_INS_SHA3 = 32, 50 | EVM_INS_ADDRESS = 48, 51 | EVM_INS_BALANCE = 49, 52 | EVM_INS_ORIGIN = 50, 53 | EVM_INS_CALLER = 51, 54 | EVM_INS_CALLVALUE = 52, 55 | EVM_INS_CALLDATALOAD = 53, 56 | EVM_INS_CALLDATASIZE = 54, 57 | EVM_INS_CALLDATACOPY = 55, 58 | EVM_INS_CODESIZE = 56, 59 | EVM_INS_CODECOPY = 57, 60 | EVM_INS_GASPRICE = 58, 61 | EVM_INS_EXTCODESIZE = 59, 62 | EVM_INS_EXTCODECOPY = 60, 63 | EVM_INS_RETURNDATASIZE = 61, 64 | EVM_INS_RETURNDATACOPY = 62, 65 | EVM_INS_BLOCKHASH = 64, 66 | EVM_INS_COINBASE = 65, 67 | EVM_INS_TIMESTAMP = 66, 68 | EVM_INS_NUMBER = 67, 69 | EVM_INS_DIFFICULTY = 68, 70 | EVM_INS_GASLIMIT = 69, 71 | EVM_INS_POP = 80, 72 | EVM_INS_MLOAD = 81, 73 | EVM_INS_MSTORE = 82, 74 | EVM_INS_MSTORE8 = 83, 75 | EVM_INS_SLOAD = 84, 76 | EVM_INS_SSTORE = 85, 77 | EVM_INS_JUMP = 86, 78 | EVM_INS_JUMPI = 87, 79 | EVM_INS_PC = 88, 80 | EVM_INS_MSIZE = 89, 81 | EVM_INS_GAS = 90, 82 | EVM_INS_JUMPDEST = 91, 83 | EVM_INS_PUSH1 = 96, 84 | EVM_INS_PUSH2 = 97, 85 | EVM_INS_PUSH3 = 98, 86 | EVM_INS_PUSH4 = 99, 87 | EVM_INS_PUSH5 = 100, 88 | EVM_INS_PUSH6 = 101, 89 | EVM_INS_PUSH7 = 102, 90 | EVM_INS_PUSH8 = 103, 91 | EVM_INS_PUSH9 = 104, 92 | EVM_INS_PUSH10 = 105, 93 | EVM_INS_PUSH11 = 106, 94 | EVM_INS_PUSH12 = 107, 95 | EVM_INS_PUSH13 = 108, 96 | EVM_INS_PUSH14 = 109, 97 | EVM_INS_PUSH15 = 110, 98 | EVM_INS_PUSH16 = 111, 99 | EVM_INS_PUSH17 = 112, 100 | EVM_INS_PUSH18 = 113, 101 | EVM_INS_PUSH19 = 114, 102 | EVM_INS_PUSH20 = 115, 103 | EVM_INS_PUSH21 = 116, 104 | EVM_INS_PUSH22 = 117, 105 | EVM_INS_PUSH23 = 118, 106 | EVM_INS_PUSH24 = 119, 107 | EVM_INS_PUSH25 = 120, 108 | EVM_INS_PUSH26 = 121, 109 | EVM_INS_PUSH27 = 122, 110 | EVM_INS_PUSH28 = 123, 111 | EVM_INS_PUSH29 = 124, 112 | EVM_INS_PUSH30 = 125, 113 | EVM_INS_PUSH31 = 126, 114 | EVM_INS_PUSH32 = 127, 115 | EVM_INS_DUP1 = 128, 116 | EVM_INS_DUP2 = 129, 117 | EVM_INS_DUP3 = 130, 118 | EVM_INS_DUP4 = 131, 119 | EVM_INS_DUP5 = 132, 120 | EVM_INS_DUP6 = 133, 121 | EVM_INS_DUP7 = 134, 122 | EVM_INS_DUP8 = 135, 123 | EVM_INS_DUP9 = 136, 124 | EVM_INS_DUP10 = 137, 125 | EVM_INS_DUP11 = 138, 126 | EVM_INS_DUP12 = 139, 127 | EVM_INS_DUP13 = 140, 128 | EVM_INS_DUP14 = 141, 129 | EVM_INS_DUP15 = 142, 130 | EVM_INS_DUP16 = 143, 131 | EVM_INS_SWAP1 = 144, 132 | EVM_INS_SWAP2 = 145, 133 | EVM_INS_SWAP3 = 146, 134 | EVM_INS_SWAP4 = 147, 135 | EVM_INS_SWAP5 = 148, 136 | EVM_INS_SWAP6 = 149, 137 | EVM_INS_SWAP7 = 150, 138 | EVM_INS_SWAP8 = 151, 139 | EVM_INS_SWAP9 = 152, 140 | EVM_INS_SWAP10 = 153, 141 | EVM_INS_SWAP11 = 154, 142 | EVM_INS_SWAP12 = 155, 143 | EVM_INS_SWAP13 = 156, 144 | EVM_INS_SWAP14 = 157, 145 | EVM_INS_SWAP15 = 158, 146 | EVM_INS_SWAP16 = 159, 147 | EVM_INS_LOG0 = 160, 148 | EVM_INS_LOG1 = 161, 149 | EVM_INS_LOG2 = 162, 150 | EVM_INS_LOG3 = 163, 151 | EVM_INS_LOG4 = 164, 152 | EVM_INS_CREATE = 240, 153 | EVM_INS_CALL = 241, 154 | EVM_INS_CALLCODE = 242, 155 | EVM_INS_RETURN = 243, 156 | EVM_INS_DELEGATECALL = 244, 157 | EVM_INS_CALLBLACKBOX = 245, 158 | EVM_INS_STATICCALL = 250, 159 | EVM_INS_REVERT = 253, 160 | EVM_INS_SUICIDE = 255, 161 | 162 | EVM_INS_INVALID = 512, 163 | EVM_INS_ENDING, // <-- mark the end of the list of instructions 164 | } evm_insn; 165 | 166 | /// Group of EVM instructions 167 | typedef enum evm_insn_group { 168 | EVM_GRP_INVALID = 0, ///< = CS_GRP_INVALID 169 | 170 | EVM_GRP_JUMP, ///< all jump instructions 171 | 172 | EVM_GRP_MATH = 8, ///< math instructions 173 | EVM_GRP_STACK_WRITE, ///< instructions write to stack 174 | EVM_GRP_STACK_READ, ///< instructions read from stack 175 | EVM_GRP_MEM_WRITE, ///< instructions write to memory 176 | EVM_GRP_MEM_READ, ///< instructions read from memory 177 | EVM_GRP_STORE_WRITE, ///< instructions write to storage 178 | EVM_GRP_STORE_READ, ///< instructions read from storage 179 | EVM_GRP_HALT, ///< instructions halt execution 180 | 181 | EVM_GRP_ENDING, ///< <-- mark the end of the list of groups 182 | } evm_insn_group; 183 | 184 | #ifdef __cplusplus 185 | } 186 | #endif 187 | 188 | #endif 189 | -------------------------------------------------------------------------------- /dependencies/include/capstone/mos65xx.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPSTONE_MOS65XX_H 2 | #define CAPSTONE_MOS65XX_H 3 | 4 | /* Capstone Disassembly Engine */ 5 | /* By Sebastian Macke C99 is supported 23 | #include 24 | #endif // (_MSC_VER < 1800) || defined(_KERNEL_MODE) 25 | 26 | #else 27 | // not MSVC -> C99 is supported 28 | #include 29 | #endif // !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)) 30 | 31 | 32 | // handle inttypes.h / stdint.h compatibility 33 | #if defined(_WIN32_WCE) && (_WIN32_WCE < 0x800) 34 | #include "windowsce/stdint.h" 35 | #endif // defined(_WIN32_WCE) && (_WIN32_WCE < 0x800) 36 | 37 | #if defined(CAPSTONE_HAS_OSXKERNEL) || (defined(_MSC_VER) && (_MSC_VER <= 1700 || defined(_KERNEL_MODE))) 38 | // this system does not have inttypes.h 39 | 40 | #if defined(_MSC_VER) && (_MSC_VER <= 1600 || defined(_KERNEL_MODE)) 41 | // this system does not have stdint.h 42 | typedef signed char int8_t; 43 | typedef signed short int16_t; 44 | typedef signed int int32_t; 45 | typedef unsigned char uint8_t; 46 | typedef unsigned short uint16_t; 47 | typedef unsigned int uint32_t; 48 | typedef signed long long int64_t; 49 | typedef unsigned long long uint64_t; 50 | #endif // defined(_MSC_VER) && (_MSC_VER <= 1600 || defined(_KERNEL_MODE)) 51 | 52 | #if defined(_MSC_VER) && (_MSC_VER < 1600 || defined(_KERNEL_MODE)) 53 | #define INT8_MIN (-127i8 - 1) 54 | #define INT16_MIN (-32767i16 - 1) 55 | #define INT32_MIN (-2147483647i32 - 1) 56 | #define INT64_MIN (-9223372036854775807i64 - 1) 57 | #define INT8_MAX 127i8 58 | #define INT16_MAX 32767i16 59 | #define INT32_MAX 2147483647i32 60 | #define INT64_MAX 9223372036854775807i64 61 | #define UINT8_MAX 0xffui8 62 | #define UINT16_MAX 0xffffui16 63 | #define UINT32_MAX 0xffffffffui32 64 | #define UINT64_MAX 0xffffffffffffffffui64 65 | #endif // defined(_MSC_VER) && (_MSC_VER < 1600 || defined(_KERNEL_MODE)) 66 | 67 | #ifdef CAPSTONE_HAS_OSXKERNEL 68 | // this system has stdint.h 69 | #include 70 | #endif 71 | 72 | #define __PRI_8_LENGTH_MODIFIER__ "hh" 73 | #define __PRI_64_LENGTH_MODIFIER__ "ll" 74 | 75 | #define PRId8 __PRI_8_LENGTH_MODIFIER__ "d" 76 | #define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i" 77 | #define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o" 78 | #define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u" 79 | #define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x" 80 | #define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X" 81 | 82 | #define PRId16 "hd" 83 | #define PRIi16 "hi" 84 | #define PRIo16 "ho" 85 | #define PRIu16 "hu" 86 | #define PRIx16 "hx" 87 | #define PRIX16 "hX" 88 | 89 | #if defined(_MSC_VER) && _MSC_VER <= 1700 90 | #define PRId32 "ld" 91 | #define PRIi32 "li" 92 | #define PRIo32 "lo" 93 | #define PRIu32 "lu" 94 | #define PRIx32 "lx" 95 | #define PRIX32 "lX" 96 | #else // OSX 97 | #define PRId32 "d" 98 | #define PRIi32 "i" 99 | #define PRIo32 "o" 100 | #define PRIu32 "u" 101 | #define PRIx32 "x" 102 | #define PRIX32 "X" 103 | #endif // defined(_MSC_VER) && _MSC_VER <= 1700 104 | 105 | #if defined(_MSC_VER) && _MSC_VER <= 1700 106 | // redefine functions from inttypes.h used in cstool 107 | #define strtoull _strtoui64 108 | #endif 109 | 110 | #define PRId64 __PRI_64_LENGTH_MODIFIER__ "d" 111 | #define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i" 112 | #define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o" 113 | #define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u" 114 | #define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x" 115 | #define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X" 116 | 117 | #else 118 | // this system has inttypes.h by default 119 | #include 120 | #endif // defined(CAPSTONE_HAS_OSXKERNEL) || (defined(_MSC_VER) && (_MSC_VER <= 1700 || defined(_KERNEL_MODE))) 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /dependencies/include/capstone/xcore.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPSTONE_XCORE_H 2 | #define CAPSTONE_XCORE_H 3 | 4 | /* Capstone Disassembly Engine */ 5 | /* By Nguyen Anh Quynh , 2014-2015 */ 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #include "platform.h" 12 | 13 | #ifdef _MSC_VER 14 | #pragma warning(disable:4201) 15 | #endif 16 | 17 | /// Operand type for instruction's operands 18 | typedef enum xcore_op_type { 19 | XCORE_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized). 20 | XCORE_OP_REG, ///< = CS_OP_REG (Register operand). 21 | XCORE_OP_IMM, ///< = CS_OP_IMM (Immediate operand). 22 | XCORE_OP_MEM, ///< = CS_OP_MEM (Memory operand). 23 | } xcore_op_type; 24 | 25 | /// XCore registers 26 | typedef enum xcore_reg { 27 | XCORE_REG_INVALID = 0, 28 | 29 | XCORE_REG_CP, 30 | XCORE_REG_DP, 31 | XCORE_REG_LR, 32 | XCORE_REG_SP, 33 | XCORE_REG_R0, 34 | XCORE_REG_R1, 35 | XCORE_REG_R2, 36 | XCORE_REG_R3, 37 | XCORE_REG_R4, 38 | XCORE_REG_R5, 39 | XCORE_REG_R6, 40 | XCORE_REG_R7, 41 | XCORE_REG_R8, 42 | XCORE_REG_R9, 43 | XCORE_REG_R10, 44 | XCORE_REG_R11, 45 | 46 | // pseudo registers 47 | XCORE_REG_PC, 48 | 49 | // internal thread registers 50 | // see The-XMOS-XS1-Architecture(X7879A).pdf 51 | XCORE_REG_SCP, 52 | XCORE_REG_SSR, 53 | XCORE_REG_ET, 54 | XCORE_REG_ED, 55 | XCORE_REG_SED, 56 | XCORE_REG_KEP, 57 | XCORE_REG_KSP, 58 | XCORE_REG_ID, 59 | 60 | XCORE_REG_ENDING, // <-- mark the end of the list of registers 61 | } xcore_reg; 62 | 63 | /// Instruction's operand referring to memory 64 | /// This is associated with XCORE_OP_MEM operand type above 65 | typedef struct xcore_op_mem { 66 | uint8_t base; ///< base register, can be safely interpreted as 67 | ///< a value of type `xcore_reg`, but it is only 68 | ///< one byte wide 69 | uint8_t index; ///< index register, same conditions apply here 70 | int32_t disp; ///< displacement/offset value 71 | int direct; ///< +1: forward, -1: backward 72 | } xcore_op_mem; 73 | 74 | /// Instruction operand 75 | typedef struct cs_xcore_op { 76 | xcore_op_type type; ///< operand type 77 | union { 78 | xcore_reg reg; ///< register value for REG operand 79 | int32_t imm; ///< immediate value for IMM operand 80 | xcore_op_mem mem; ///< base/disp value for MEM operand 81 | }; 82 | } cs_xcore_op; 83 | 84 | /// Instruction structure 85 | typedef struct cs_xcore { 86 | /// Number of operands of this instruction, 87 | /// or 0 when instruction has no operand. 88 | uint8_t op_count; 89 | cs_xcore_op operands[8]; ///< operands for this instruction. 90 | } cs_xcore; 91 | 92 | /// XCore instruction 93 | typedef enum xcore_insn { 94 | XCORE_INS_INVALID = 0, 95 | 96 | XCORE_INS_ADD, 97 | XCORE_INS_ANDNOT, 98 | XCORE_INS_AND, 99 | XCORE_INS_ASHR, 100 | XCORE_INS_BAU, 101 | XCORE_INS_BITREV, 102 | XCORE_INS_BLA, 103 | XCORE_INS_BLAT, 104 | XCORE_INS_BL, 105 | XCORE_INS_BF, 106 | XCORE_INS_BT, 107 | XCORE_INS_BU, 108 | XCORE_INS_BRU, 109 | XCORE_INS_BYTEREV, 110 | XCORE_INS_CHKCT, 111 | XCORE_INS_CLRE, 112 | XCORE_INS_CLRPT, 113 | XCORE_INS_CLRSR, 114 | XCORE_INS_CLZ, 115 | XCORE_INS_CRC8, 116 | XCORE_INS_CRC32, 117 | XCORE_INS_DCALL, 118 | XCORE_INS_DENTSP, 119 | XCORE_INS_DGETREG, 120 | XCORE_INS_DIVS, 121 | XCORE_INS_DIVU, 122 | XCORE_INS_DRESTSP, 123 | XCORE_INS_DRET, 124 | XCORE_INS_ECALLF, 125 | XCORE_INS_ECALLT, 126 | XCORE_INS_EDU, 127 | XCORE_INS_EEF, 128 | XCORE_INS_EET, 129 | XCORE_INS_EEU, 130 | XCORE_INS_ENDIN, 131 | XCORE_INS_ENTSP, 132 | XCORE_INS_EQ, 133 | XCORE_INS_EXTDP, 134 | XCORE_INS_EXTSP, 135 | XCORE_INS_FREER, 136 | XCORE_INS_FREET, 137 | XCORE_INS_GETD, 138 | XCORE_INS_GET, 139 | XCORE_INS_GETN, 140 | XCORE_INS_GETR, 141 | XCORE_INS_GETSR, 142 | XCORE_INS_GETST, 143 | XCORE_INS_GETTS, 144 | XCORE_INS_INCT, 145 | XCORE_INS_INIT, 146 | XCORE_INS_INPW, 147 | XCORE_INS_INSHR, 148 | XCORE_INS_INT, 149 | XCORE_INS_IN, 150 | XCORE_INS_KCALL, 151 | XCORE_INS_KENTSP, 152 | XCORE_INS_KRESTSP, 153 | XCORE_INS_KRET, 154 | XCORE_INS_LADD, 155 | XCORE_INS_LD16S, 156 | XCORE_INS_LD8U, 157 | XCORE_INS_LDA16, 158 | XCORE_INS_LDAP, 159 | XCORE_INS_LDAW, 160 | XCORE_INS_LDC, 161 | XCORE_INS_LDW, 162 | XCORE_INS_LDIVU, 163 | XCORE_INS_LMUL, 164 | XCORE_INS_LSS, 165 | XCORE_INS_LSUB, 166 | XCORE_INS_LSU, 167 | XCORE_INS_MACCS, 168 | XCORE_INS_MACCU, 169 | XCORE_INS_MJOIN, 170 | XCORE_INS_MKMSK, 171 | XCORE_INS_MSYNC, 172 | XCORE_INS_MUL, 173 | XCORE_INS_NEG, 174 | XCORE_INS_NOT, 175 | XCORE_INS_OR, 176 | XCORE_INS_OUTCT, 177 | XCORE_INS_OUTPW, 178 | XCORE_INS_OUTSHR, 179 | XCORE_INS_OUTT, 180 | XCORE_INS_OUT, 181 | XCORE_INS_PEEK, 182 | XCORE_INS_REMS, 183 | XCORE_INS_REMU, 184 | XCORE_INS_RETSP, 185 | XCORE_INS_SETCLK, 186 | XCORE_INS_SET, 187 | XCORE_INS_SETC, 188 | XCORE_INS_SETD, 189 | XCORE_INS_SETEV, 190 | XCORE_INS_SETN, 191 | XCORE_INS_SETPSC, 192 | XCORE_INS_SETPT, 193 | XCORE_INS_SETRDY, 194 | XCORE_INS_SETSR, 195 | XCORE_INS_SETTW, 196 | XCORE_INS_SETV, 197 | XCORE_INS_SEXT, 198 | XCORE_INS_SHL, 199 | XCORE_INS_SHR, 200 | XCORE_INS_SSYNC, 201 | XCORE_INS_ST16, 202 | XCORE_INS_ST8, 203 | XCORE_INS_STW, 204 | XCORE_INS_SUB, 205 | XCORE_INS_SYNCR, 206 | XCORE_INS_TESTCT, 207 | XCORE_INS_TESTLCL, 208 | XCORE_INS_TESTWCT, 209 | XCORE_INS_TSETMR, 210 | XCORE_INS_START, 211 | XCORE_INS_WAITEF, 212 | XCORE_INS_WAITET, 213 | XCORE_INS_WAITEU, 214 | XCORE_INS_XOR, 215 | XCORE_INS_ZEXT, 216 | 217 | XCORE_INS_ENDING, // <-- mark the end of the list of instructions 218 | } xcore_insn; 219 | 220 | /// Group of XCore instructions 221 | typedef enum xcore_insn_group { 222 | XCORE_GRP_INVALID = 0, ///< = CS_GRP_INVALID 223 | 224 | // Generic groups 225 | // all jump instructions (conditional+direct+indirect jumps) 226 | XCORE_GRP_JUMP, ///< = CS_GRP_JUMP 227 | 228 | XCORE_GRP_ENDING, // <-- mark the end of the list of groups 229 | } xcore_insn_group; 230 | 231 | #ifdef __cplusplus 232 | } 233 | #endif 234 | 235 | #endif 236 | -------------------------------------------------------------------------------- /dependencies/include/json-c/arraylist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | /** 13 | * @file 14 | * @brief Internal methods for working with json_type_array objects. 15 | * Although this is exposed by the json_object_get_array() method, 16 | * it is not recommended for direct use. 17 | */ 18 | #ifndef _json_c_arraylist_h_ 19 | #define _json_c_arraylist_h_ 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | #include 26 | 27 | #define ARRAY_LIST_DEFAULT_SIZE 32 28 | 29 | typedef void(array_list_free_fn)(void *data); 30 | 31 | struct array_list 32 | { 33 | void **array; 34 | size_t length; 35 | size_t size; 36 | array_list_free_fn *free_fn; 37 | }; 38 | typedef struct array_list array_list; 39 | 40 | /** 41 | * Allocate an array_list of the default size (32). 42 | * @deprecated Use array_list_new2() instead. 43 | */ 44 | extern struct array_list *array_list_new(array_list_free_fn *free_fn); 45 | 46 | /** 47 | * Allocate an array_list of the desired size. 48 | * 49 | * If possible, the size should be chosen to closely match 50 | * the actual number of elements expected to be used. 51 | * If the exact size is unknown, there are tradeoffs to be made: 52 | * - too small - the array_list code will need to call realloc() more 53 | * often (which might incur an additional memory copy). 54 | * - too large - will waste memory, but that can be mitigated 55 | * by calling array_list_shrink() once the final size is known. 56 | * 57 | * @see array_list_shrink 58 | */ 59 | extern struct array_list *array_list_new2(array_list_free_fn *free_fn, int initial_size); 60 | 61 | extern void array_list_free(struct array_list *al); 62 | 63 | extern void *array_list_get_idx(struct array_list *al, size_t i); 64 | 65 | extern int array_list_insert_idx(struct array_list *al, size_t i, void *data); 66 | 67 | extern int array_list_put_idx(struct array_list *al, size_t i, void *data); 68 | 69 | extern int array_list_add(struct array_list *al, void *data); 70 | 71 | extern size_t array_list_length(struct array_list *al); 72 | 73 | extern void array_list_sort(struct array_list *arr, int (*compar)(const void *, const void *)); 74 | 75 | extern void *array_list_bsearch(const void **key, struct array_list *arr, 76 | int (*compar)(const void *, const void *)); 77 | 78 | extern int array_list_del_idx(struct array_list *arr, size_t idx, size_t count); 79 | 80 | /** 81 | * Shrink the array list to just enough to fit the number of elements in it, 82 | * plus empty_slots. 83 | */ 84 | extern int array_list_shrink(struct array_list *arr, size_t empty_slots); 85 | 86 | #ifdef __cplusplus 87 | } 88 | #endif 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /dependencies/include/json-c/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. 7 | * 8 | * This library is free software; you can redistribute it and/or modify 9 | * it under the terms of the MIT license. See COPYING for details. 10 | * 11 | */ 12 | 13 | /** 14 | * @file 15 | * @brief Do not use, json-c internal, may be changed or removed at any time. 16 | */ 17 | #ifndef _JSON_C_DEBUG_H_ 18 | #define _JSON_C_DEBUG_H_ 19 | 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #ifndef JSON_EXPORT 27 | #if defined(_MSC_VER) && defined(JSON_C_DLL) 28 | #define JSON_EXPORT __declspec(dllexport) 29 | #else 30 | #define JSON_EXPORT extern 31 | #endif 32 | #endif 33 | 34 | JSON_EXPORT void mc_set_debug(int debug); 35 | JSON_EXPORT int mc_get_debug(void); 36 | 37 | JSON_EXPORT void mc_set_syslog(int syslog); 38 | 39 | JSON_EXPORT void mc_debug(const char *msg, ...); 40 | JSON_EXPORT void mc_error(const char *msg, ...); 41 | JSON_EXPORT void mc_info(const char *msg, ...); 42 | 43 | #ifndef __STRING 44 | #define __STRING(x) #x 45 | #endif 46 | 47 | #ifndef PARSER_BROKEN_FIXED 48 | 49 | #define JASSERT(cond) \ 50 | do \ 51 | { \ 52 | } while (0) 53 | 54 | #else 55 | 56 | #define JASSERT(cond) \ 57 | do \ 58 | { \ 59 | if (!(cond)) \ 60 | { \ 61 | mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", \ 62 | __FILE__, __LINE__); \ 63 | *(int *)0 = 1; \ 64 | abort(); \ 65 | } \ 66 | } while (0) 67 | 68 | #endif 69 | 70 | #define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) 71 | 72 | #ifdef MC_MAINTAINER_MODE 73 | #define MC_SET_DEBUG(x) mc_set_debug(x) 74 | #define MC_GET_DEBUG() mc_get_debug() 75 | #define MC_SET_SYSLOG(x) mc_set_syslog(x) 76 | #define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) 77 | #define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__) 78 | #else 79 | #define MC_SET_DEBUG(x) \ 80 | if (0) \ 81 | mc_set_debug(x) 82 | #define MC_GET_DEBUG() (0) 83 | #define MC_SET_SYSLOG(x) \ 84 | if (0) \ 85 | mc_set_syslog(x) 86 | #define MC_DEBUG(x, ...) \ 87 | if (0) \ 88 | mc_debug(x, ##__VA_ARGS__) 89 | #define MC_INFO(x, ...) \ 90 | if (0) \ 91 | mc_info(x, ##__VA_ARGS__) 92 | #endif 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_c_version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012,2017 Eric Haszlakiewicz 3 | * 4 | * This library is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See COPYING for details. 6 | */ 7 | 8 | /** 9 | * @file 10 | * @brief Methods for retrieving the json-c version. 11 | */ 12 | #ifndef _json_c_version_h_ 13 | #define _json_c_version_h_ 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #define JSON_C_MAJOR_VERSION 0 20 | #define JSON_C_MINOR_VERSION 18 21 | #define JSON_C_MICRO_VERSION 99 22 | #define JSON_C_VERSION_NUM \ 23 | ((JSON_C_MAJOR_VERSION << 16) | (JSON_C_MINOR_VERSION << 8) | JSON_C_MICRO_VERSION) 24 | #define JSON_C_VERSION "0.18.99" 25 | 26 | #ifndef JSON_EXPORT 27 | #if defined(_MSC_VER) && defined(JSON_C_DLL) 28 | #define JSON_EXPORT __declspec(dllexport) 29 | #else 30 | #define JSON_EXPORT extern 31 | #endif 32 | #endif 33 | 34 | /** 35 | * @see JSON_C_VERSION 36 | * @return the version of the json-c library as a string 37 | */ 38 | JSON_EXPORT const char *json_c_version(void); /* Returns JSON_C_VERSION */ 39 | 40 | /** 41 | * The json-c version encoded into an int, with the low order 8 bits 42 | * being the micro version, the next higher 8 bits being the minor version 43 | * and the next higher 8 bits being the major version. 44 | * For example, 7.12.99 would be 0x00070B63. 45 | * 46 | * @see JSON_C_VERSION_NUM 47 | * @return the version of the json-c library as an int 48 | */ 49 | JSON_EXPORT int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_config.h: -------------------------------------------------------------------------------- 1 | /* Define to 1 if you have the header file. */ 2 | #define JSON_C_HAVE_INTTYPES_H 1 3 | 4 | /* Define to 1 if you have the header file. */ 5 | #define JSON_C_HAVE_STDINT_H 1 6 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_inttypes.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @file 4 | * @brief Do not use, json-c internal, may be changed or removed at any time. 5 | */ 6 | #ifndef _json_inttypes_h_ 7 | #define _json_inttypes_h_ 8 | 9 | #include "json_config.h" 10 | 11 | #ifdef JSON_C_HAVE_INTTYPES_H 12 | /* inttypes.h includes stdint.h */ 13 | #include 14 | 15 | #else 16 | #ifdef JSON_C_HAVE_STDINT_H 17 | #include 18 | #else 19 | /* Really only valid for old MS compilers, VS2008 and earlier: */ 20 | typedef __int32 int32_t; 21 | typedef unsigned __int32 uint32_t; 22 | typedef __int64 int64_t; 23 | typedef unsigned __int64 uint64_t; 24 | #endif 25 | 26 | #define PRId64 "I64d" 27 | #define SCNd64 "I64d" 28 | #define PRIu64 "I64u" 29 | 30 | #endif 31 | 32 | #if defined(_MSC_VER) 33 | #include 34 | typedef SSIZE_T ssize_t; 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_object_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | /** 13 | * @file 14 | * @brief Do not use, json-c internal, may be changed or removed at any time. 15 | */ 16 | #ifndef _json_object_private_h_ 17 | #define _json_object_private_h_ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | struct json_object; 24 | #include "json_inttypes.h" 25 | #include "json_types.h" 26 | 27 | #ifdef HAVE_UNISTD_H 28 | #include 29 | #endif /* HAVE_UNISTD_H */ 30 | 31 | #ifdef _MSC_VER 32 | #include 33 | typedef SSIZE_T ssize_t; 34 | #endif 35 | 36 | /* json object int type, support extension*/ 37 | typedef enum json_object_int_type 38 | { 39 | json_object_int_type_int64, 40 | json_object_int_type_uint64 41 | } json_object_int_type; 42 | 43 | struct json_object 44 | { 45 | enum json_type o_type; 46 | uint32_t _ref_count; 47 | json_object_to_json_string_fn *_to_json_string; 48 | struct printbuf *_pb; 49 | json_object_delete_fn *_user_delete; 50 | void *_userdata; 51 | // Actually longer, always malloc'd as some more-specific type. 52 | // The rest of a struct json_object_${o_type} follows 53 | }; 54 | 55 | struct json_object_object 56 | { 57 | struct json_object base; 58 | struct lh_table *c_object; 59 | }; 60 | struct json_object_array 61 | { 62 | struct json_object base; 63 | struct array_list *c_array; 64 | }; 65 | 66 | struct json_object_boolean 67 | { 68 | struct json_object base; 69 | json_bool c_boolean; 70 | }; 71 | struct json_object_double 72 | { 73 | struct json_object base; 74 | double c_double; 75 | }; 76 | struct json_object_int 77 | { 78 | struct json_object base; 79 | enum json_object_int_type cint_type; 80 | union 81 | { 82 | int64_t c_int64; 83 | uint64_t c_uint64; 84 | } cint; 85 | }; 86 | struct json_object_string 87 | { 88 | struct json_object base; 89 | ssize_t len; // Signed b/c negative lengths indicate data is a pointer 90 | // Consider adding an "alloc" field here, if json_object_set_string calls 91 | // to expand the length of a string are common operations to perform. 92 | union 93 | { 94 | char idata[1]; // Immediate data. Actually longer 95 | char *pdata; // Only when len < 0 96 | } c_string; 97 | }; 98 | 99 | void _json_c_set_last_err(const char *err_fmt, ...); 100 | 101 | extern const char *json_hex_chars; 102 | 103 | #ifdef __cplusplus 104 | } 105 | #endif 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_patch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Alexadru Ardelean. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See COPYING for details. 6 | * 7 | */ 8 | 9 | /** 10 | * @file 11 | * @brief JSON Patch (RFC 6902) implementation for manipulating JSON objects 12 | */ 13 | #ifndef _json_patch_h_ 14 | #define _json_patch_h_ 15 | 16 | #include "json_pointer.h" 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /** 23 | * Details of an error that occurred during json_patch_apply() 24 | */ 25 | struct json_patch_error { 26 | /** 27 | * An errno value indicating what kind of error occurred. 28 | * Possible values include: 29 | * - ENOENT - A path referenced in the operation does not exist. 30 | * - EINVAL - An invalid operation or with invalid path was attempted 31 | * - ENOMEM - Unable to allocate memory 32 | * - EFAULT - Invalid arguments were passed to json_patch_apply() 33 | * (i.e. a C API error, vs. a data error like EINVAL) 34 | */ 35 | int errno_code; 36 | 37 | /** 38 | * The index into the patch array of the operation that failed, 39 | * or SIZE_T_MAX for overall errors. 40 | */ 41 | size_t patch_failure_idx; 42 | 43 | /** 44 | * A human readable error message. 45 | * Allocated from static storage, does not need to be freed. 46 | */ 47 | const char *errmsg; 48 | }; 49 | 50 | /** 51 | * Apply the JSON patch to the base object. 52 | * The patch object must be formatted as per RFC 6902, i.e. 53 | * a json_type_array containing patch operations. 54 | * If the patch is not correctly formatted, an error will 55 | * be returned. 56 | * 57 | * The json_object at *base will be modified in place. 58 | * Exactly one of *base or copy_from must be non-NULL. 59 | * If *base is NULL, a new copy of copy_from will allocated and populated 60 | * using json_object_deep_copy(). In this case json_object_put() _must_ be 61 | * used to free *base even if the overall patching operation fails. 62 | * 63 | * If anything fails during patching a negative value will be returned, 64 | * and patch_error (if non-NULL) will be populated with error details. 65 | * 66 | * @param base a pointer to the JSON object which to patch 67 | * @param patch the JSON object that describes the patch to be applied 68 | * @param copy_from a JSON object to copy to *base 69 | * @param patch_error optional, details about errors 70 | * 71 | * @return negative if an error (or not found), or 0 if patch completely applied 72 | */ 73 | JSON_EXPORT int json_patch_apply(struct json_object *copy_from, struct json_object *patch, 74 | struct json_object **base, struct json_patch_error *patch_error); 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_pointer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Alexadru Ardelean. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See COPYING for details. 6 | * 7 | */ 8 | 9 | /** 10 | * @file 11 | * @brief JSON Pointer (RFC 6901) implementation for retrieving 12 | * objects from a json-c object tree. 13 | */ 14 | #ifndef _json_pointer_h_ 15 | #define _json_pointer_h_ 16 | 17 | #include "json_object.h" 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** 24 | * Retrieves a JSON sub-object from inside another JSON object 25 | * using the JSON pointer notation as defined in RFC 6901 26 | * https://tools.ietf.org/html/rfc6901 27 | * 28 | * The returned JSON sub-object is equivalent to parsing manually the 29 | * 'obj' JSON tree ; i.e. it's not a new object that is created, but rather 30 | * a pointer inside the JSON tree. 31 | * 32 | * Internally, this is equivalent to doing a series of 'json_object_object_get()' 33 | * and 'json_object_array_get_idx()' along the given 'path'. 34 | * 35 | * @param obj the json_object instance/tree from where to retrieve sub-objects 36 | * @param path a (RFC6901) string notation for the sub-object to retrieve 37 | * @param res a pointer that stores a reference to the json_object 38 | * associated with the given path 39 | * 40 | * @return negative if an error (or not found), or 0 if succeeded 41 | */ 42 | JSON_EXPORT int json_pointer_get(struct json_object *obj, const char *path, 43 | struct json_object **res); 44 | 45 | /** 46 | * This is a variant of 'json_pointer_get()' that supports printf() style arguments. 47 | * 48 | * Variable arguments go after the 'path_fmt' parameter. 49 | * 50 | * Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, "bar") 51 | * This also means that you need to escape '%' with '%%' (just like in printf()) 52 | * 53 | * Please take into consideration all recommended 'printf()' format security 54 | * aspects when using this function. 55 | * 56 | * @param obj the json_object instance/tree to which to add a sub-object 57 | * @param res a pointer that stores a reference to the json_object 58 | * associated with the given path 59 | * @param path_fmt a printf() style format for the path 60 | * 61 | * @return negative if an error (or not found), or 0 if succeeded 62 | */ 63 | JSON_EXPORT int json_pointer_getf(struct json_object *obj, struct json_object **res, 64 | const char *path_fmt, ...); 65 | 66 | /** 67 | * Sets JSON object 'value' in the 'obj' tree at the location specified 68 | * by the 'path'. 'path' is JSON pointer notation as defined in RFC 6901 69 | * https://tools.ietf.org/html/rfc6901 70 | * 71 | * Note that 'obj' is a double pointer, mostly for the "" (empty string) 72 | * case, where the entire JSON object would be replaced by 'value'. 73 | * In the case of the "" path, the object at '*obj' will have it's refcount 74 | * decremented with 'json_object_put()' and the 'value' object will be assigned to it. 75 | * 76 | * For other cases (JSON sub-objects) ownership of 'value' will be transferred into 77 | * '*obj' via 'json_object_object_add()' & 'json_object_array_put_idx()', so the 78 | * only time the refcount should be decremented for 'value' is when the return value of 79 | * 'json_pointer_set()' is negative (meaning the 'value' object did not get set into '*obj'). 80 | * 81 | * That also implies that 'json_pointer_set()' does not do any refcount incrementing. 82 | * (Just that single decrement that was mentioned above). 83 | * 84 | * @param obj the json_object instance/tree to which to add a sub-object 85 | * @param path a (RFC6901) string notation for the sub-object to set in the tree 86 | * @param value object to set at path 87 | * 88 | * @return negative if an error (or not found), or 0 if succeeded 89 | */ 90 | JSON_EXPORT int json_pointer_set(struct json_object **obj, const char *path, 91 | struct json_object *value); 92 | 93 | /** 94 | * This is a variant of 'json_pointer_set()' that supports printf() style arguments. 95 | * 96 | * Variable arguments go after the 'path_fmt' parameter. 97 | * 98 | * Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, "bar") 99 | * This also means that you need to escape '%' with '%%' (just like in printf()) 100 | * 101 | * Please take into consideration all recommended 'printf()' format security 102 | * aspects when using this function. 103 | * 104 | * @param obj the json_object instance/tree to which to add a sub-object 105 | * @param value object to set at path 106 | * @param path_fmt a printf() style format for the path 107 | * 108 | * @return negative if an error (or not found), or 0 if succeeded 109 | */ 110 | JSON_EXPORT int json_pointer_setf(struct json_object **obj, struct json_object *value, 111 | const char *path_fmt, ...); 112 | 113 | #ifdef __cplusplus 114 | } 115 | #endif 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_pointer_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Eric Hawicz 3 | * 4 | * This library is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See COPYING for details. 6 | */ 7 | 8 | /** 9 | * @file 10 | * @brief Do not use, json-c internal, may be changed or removed at any time. 11 | */ 12 | #ifndef _json_pointer_private_h_ 13 | #define _json_pointer_private_h_ 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | struct json_pointer_get_result { 20 | struct json_object *parent; 21 | struct json_object *obj; 22 | // The key of the found object; only valid when parent is json_type_object 23 | // Caution: re-uses tail end of the `path` argument to json_pointer_get_internal 24 | const char *key_in_parent; 25 | // the index of the found object; only valid when parent is json_type_array 26 | uint32_t index_in_parent; 27 | }; 28 | 29 | int json_pointer_get_internal(struct json_object *obj, const char *path, 30 | struct json_pointer_get_result *res); 31 | 32 | typedef int(*json_pointer_array_set_cb)(json_object *parent, size_t idx, 33 | json_object *value, void *priv); 34 | 35 | int json_pointer_set_with_array_cb(struct json_object **obj, const char *path, 36 | struct json_object *value, 37 | json_pointer_array_set_cb array_set_cb, void *priv); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Eric Hawicz 3 | * 4 | * This library is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See COPYING for details. 6 | */ 7 | 8 | #ifndef _json_types_h_ 9 | #define _json_types_h_ 10 | 11 | /** 12 | * @file 13 | * @brief Basic types used in a few places in json-c, but you should include "json_object.h" instead. 14 | */ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #ifndef JSON_EXPORT 21 | #if defined(_MSC_VER) && defined(JSON_C_DLL) 22 | #define JSON_EXPORT __declspec(dllexport) 23 | #else 24 | #define JSON_EXPORT extern 25 | #endif 26 | #endif 27 | 28 | struct printbuf; 29 | 30 | /** 31 | * A structure to use with json_object_object_foreachC() loops. 32 | * Contains key, val and entry members. 33 | */ 34 | struct json_object_iter 35 | { 36 | char *key; 37 | struct json_object *val; 38 | struct lh_entry *entry; 39 | }; 40 | typedef struct json_object_iter json_object_iter; 41 | 42 | typedef int json_bool; 43 | 44 | /** 45 | * @brief The core type for all type of JSON objects handled by json-c 46 | */ 47 | typedef struct json_object json_object; 48 | 49 | /** 50 | * Type of custom user delete functions. See json_object_set_serializer. 51 | */ 52 | typedef void(json_object_delete_fn)(struct json_object *jso, void *userdata); 53 | 54 | /** 55 | * Type of a custom serialization function. See json_object_set_serializer. 56 | */ 57 | typedef int(json_object_to_json_string_fn)(struct json_object *jso, struct printbuf *pb, int level, 58 | int flags); 59 | 60 | /* supported object types */ 61 | 62 | typedef enum json_type 63 | { 64 | /* If you change this, be sure to update json_type_to_name() too */ 65 | json_type_null, 66 | json_type_boolean, 67 | json_type_double, 68 | json_type_int, 69 | json_type_object, 70 | json_type_array, 71 | json_type_string 72 | } json_type; 73 | 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | /** 13 | * @file 14 | * @brief Miscllaneous utility functions and macros. 15 | */ 16 | #ifndef _json_util_h_ 17 | #define _json_util_h_ 18 | 19 | #include "json_object.h" 20 | 21 | #ifndef json_min 22 | #define json_min(a, b) ((a) < (b) ? (a) : (b)) 23 | #endif 24 | 25 | #ifndef json_max 26 | #define json_max(a, b) ((a) > (b) ? (a) : (b)) 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #define JSON_FILE_BUF_SIZE 4096 34 | 35 | /* utility functions */ 36 | /** 37 | * Read the full contents of the given file, then convert it to a 38 | * json_object using json_tokener_parse(). 39 | * 40 | * Returns NULL on failure. See json_util_get_last_err() for details. 41 | */ 42 | JSON_EXPORT struct json_object *json_object_from_file(const char *filename); 43 | 44 | /** 45 | * Create a JSON object from already opened file descriptor. 46 | * 47 | * This function can be helpful, when you opened the file already, 48 | * e.g. when you have a temp file. 49 | * Note, that the fd must be readable at the actual position, i.e. 50 | * use lseek(fd, 0, SEEK_SET) before. 51 | * 52 | * The depth argument specifies the maximum object depth to pass to 53 | * json_tokener_new_ex(). When depth == -1, JSON_TOKENER_DEFAULT_DEPTH 54 | * is used instead. 55 | * 56 | * Returns NULL on failure. See json_util_get_last_err() for details. 57 | */ 58 | JSON_EXPORT struct json_object *json_object_from_fd_ex(int fd, int depth); 59 | 60 | /** 61 | * Create a JSON object from an already opened file descriptor, using 62 | * the default maximum object depth. (JSON_TOKENER_DEFAULT_DEPTH) 63 | * 64 | * See json_object_from_fd_ex() for details. 65 | */ 66 | JSON_EXPORT struct json_object *json_object_from_fd(int fd); 67 | 68 | /** 69 | * Equivalent to: 70 | * json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); 71 | * 72 | * Returns -1 if something fails. See json_util_get_last_err() for details. 73 | */ 74 | JSON_EXPORT int json_object_to_file(const char *filename, struct json_object *obj); 75 | 76 | /** 77 | * Open and truncate the given file, creating it if necessary, then 78 | * convert the json_object to a string and write it to the file. 79 | * 80 | * Returns -1 if something fails. See json_util_get_last_err() for details. 81 | */ 82 | JSON_EXPORT int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); 83 | 84 | /** 85 | * Convert the json_object to a string and write it to the file descriptor. 86 | * Handles partial writes and will keep writing until done, or an error 87 | * occurs. 88 | * 89 | * @param fd an open, writable file descriptor to write to 90 | * @param obj the object to serializer and write 91 | * @param flags flags to pass to json_object_to_json_string_ext() 92 | * @return -1 if something fails. See json_util_get_last_err() for details. 93 | */ 94 | JSON_EXPORT int json_object_to_fd(int fd, struct json_object *obj, int flags); 95 | 96 | /** 97 | * Return the last error from various json-c functions, including: 98 | * json_object_to_file{,_ext}, json_object_to_fd() or 99 | * json_object_from_{file,fd}, or NULL if there is none. 100 | */ 101 | JSON_EXPORT const char *json_util_get_last_err(void); 102 | 103 | /** 104 | * A parsing helper for integer values. Returns 0 on success, 105 | * with the parsed value assigned to *retval. Overflow/underflow 106 | * are NOT considered errors, but errno will be set to ERANGE, 107 | * just like the strtol/strtoll functions do. 108 | */ 109 | JSON_EXPORT int json_parse_int64(const char *buf, int64_t *retval); 110 | /** 111 | * A parsing help for integer values, providing one extra bit of 112 | * magnitude beyond json_parse_int64(). 113 | */ 114 | JSON_EXPORT int json_parse_uint64(const char *buf, uint64_t *retval); 115 | 116 | /** 117 | * @deprecated 118 | */ 119 | __attribute__((deprecated)) int json_parse_double(const char *buf, double *retval); 120 | 121 | /** 122 | * Return a string describing the type of the object. 123 | * e.g. "int", or "object", etc... 124 | */ 125 | JSON_EXPORT const char *json_type_to_name(enum json_type o_type); 126 | 127 | #ifdef __cplusplus 128 | } 129 | #endif 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /dependencies/include/json-c/json_visit.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _json_c_json_visit_h_ 3 | #define _json_c_json_visit_h_ 4 | 5 | /** 6 | * @file 7 | * @brief Methods for walking a tree of objects. 8 | */ 9 | #include "json_object.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | typedef int(json_c_visit_userfunc)(json_object *jso, int flags, json_object *parent_jso, 16 | const char *jso_key, size_t *jso_index, void *userarg); 17 | 18 | /** 19 | * Visit each object in the JSON hierarchy starting at jso. 20 | * For each object, userfunc is called, passing the object and userarg. 21 | * If the object has a parent (i.e. anything other than jso itself) 22 | * its parent will be passed as parent_jso, and either jso_key or jso_index 23 | * will be set, depending on whether the parent is an object or an array. 24 | * 25 | * Nodes will be visited depth first, but containers (arrays and objects) 26 | * will be visited twice, the second time with JSON_C_VISIT_SECOND set in 27 | * flags. 28 | * 29 | * userfunc must return one of the defined return values, to indicate 30 | * whether and how to continue visiting nodes, or one of various ways to stop. 31 | * 32 | * Returns 0 if nodes were visited successfully, even if some were 33 | * intentionally skipped due to what userfunc returned. 34 | * Returns <0 if an error occurred during iteration, including if 35 | * userfunc returned JSON_C_VISIT_RETURN_ERROR. 36 | */ 37 | JSON_EXPORT int json_c_visit(json_object *jso, int future_flags, json_c_visit_userfunc *userfunc, 38 | void *userarg); 39 | 40 | /** 41 | * Passed to json_c_visit_userfunc as one of the flags values to indicate 42 | * that this is the second time a container (array or object) is being 43 | * called, after all of it's members have been iterated over. 44 | */ 45 | #define JSON_C_VISIT_SECOND 0x02 46 | 47 | /** 48 | * This json_c_visit_userfunc return value indicates that iteration 49 | * should proceed normally. 50 | */ 51 | #define JSON_C_VISIT_RETURN_CONTINUE 0 52 | 53 | /** 54 | * This json_c_visit_userfunc return value indicates that iteration 55 | * over the members of the current object should be skipped. 56 | * If the current object isn't a container (array or object), this 57 | * is no different than JSON_C_VISIT_RETURN_CONTINUE. 58 | */ 59 | #define JSON_C_VISIT_RETURN_SKIP 7547 60 | 61 | /** 62 | * This json_c_visit_userfunc return value indicates that iteration 63 | * of the fields/elements of the containing object should stop 64 | * and continue "popped up" a level of the object hierarchy. 65 | * For example, returning this when handling arg will result in 66 | * arg3 and any other fields being skipped. The next call to userfunc 67 | * will be the JSON_C_VISIT_SECOND call on "foo", followed by a userfunc 68 | * call on "bar". 69 | *
 70 |  * {
 71 |  *   "foo": {
 72 |  *     "arg1": 1,
 73 |  *     "arg2": 2,
 74 |  *     "arg3": 3,
 75 |  *     ...
 76 |  *   },
 77 |  *   "bar": {
 78 |  *     ...
 79 |  *   }
 80 |  * }
 81 |  * 
82 | */ 83 | #define JSON_C_VISIT_RETURN_POP 767 84 | 85 | /** 86 | * This json_c_visit_userfunc return value indicates that iteration 87 | * should stop immediately, and cause json_c_visit to return success. 88 | */ 89 | #define JSON_C_VISIT_RETURN_STOP 7867 90 | 91 | /** 92 | * This json_c_visit_userfunc return value indicates that iteration 93 | * should stop immediately, and cause json_c_visit to return an error. 94 | */ 95 | #define JSON_C_VISIT_RETURN_ERROR -1 96 | 97 | #ifdef __cplusplus 98 | } 99 | #endif 100 | 101 | #endif /* _json_c_json_visit_h_ */ 102 | -------------------------------------------------------------------------------- /dependencies/include/json-c/math_compat.h: -------------------------------------------------------------------------------- 1 | #ifndef __math_compat_h 2 | #define __math_compat_h 3 | 4 | /** 5 | * @file 6 | * @brief Do not use, json-c internal, may be changed or removed at any time. 7 | */ 8 | 9 | /* Define isnan, isinf, infinity and nan on Windows/MSVC */ 10 | 11 | #ifndef HAVE_DECL_ISNAN 12 | #ifdef HAVE_DECL__ISNAN 13 | #include 14 | #define isnan(x) _isnan(x) 15 | #else 16 | /* On platforms like AIX and "IBM i" we need to provide our own isnan */ 17 | #define isnan(x) ((x) != (x)) 18 | #endif 19 | #endif 20 | 21 | #ifndef HAVE_DECL_ISINF 22 | #ifdef HAVE_DECL__FINITE 23 | #include 24 | #define isinf(x) (!_finite(x)) 25 | #else 26 | #include 27 | /* On platforms like AIX and "IBM i" we need to provide our own isinf */ 28 | #define isinf(x) ((x) < -DBL_MAX || (x) > DBL_MAX) 29 | #endif 30 | #endif 31 | 32 | #ifndef HAVE_DECL_INFINITY 33 | #include 34 | #define INFINITY (DBL_MAX + DBL_MAX) 35 | #define HAVE_DECL_INFINITY 36 | #endif 37 | 38 | #ifndef HAVE_DECL_NAN 39 | #define NAN (INFINITY - INFINITY) 40 | #define HAVE_DECL_NAN 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /dependencies/include/json-c/printbuf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | * 11 | * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. 12 | * The copyrights to the contents of this file are licensed under the MIT License 13 | * (https://www.opensource.org/licenses/mit-license.php) 14 | */ 15 | 16 | /** 17 | * @file 18 | * @brief Internal string buffer handling. Unless you're writing a 19 | * json_object_to_json_string_fn implementation for use with 20 | * json_object_set_serializer() direct use of this is not 21 | * recommended. 22 | */ 23 | #ifndef _json_c_printbuf_h_ 24 | #define _json_c_printbuf_h_ 25 | 26 | #ifndef JSON_EXPORT 27 | #if defined(_MSC_VER) && defined(JSON_C_DLL) 28 | #define JSON_EXPORT __declspec(dllexport) 29 | #else 30 | #define JSON_EXPORT extern 31 | #endif 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | struct printbuf 39 | { 40 | char *buf; 41 | int bpos; 42 | int size; 43 | }; 44 | typedef struct printbuf printbuf; 45 | 46 | JSON_EXPORT struct printbuf *printbuf_new(void); 47 | 48 | /* As an optimization, printbuf_memappend_fast() is defined as a macro 49 | * that handles copying data if the buffer is large enough; otherwise 50 | * it invokes printbuf_memappend() which performs the heavy 51 | * lifting of realloc()ing the buffer and copying data. 52 | * 53 | * Your code should not use printbuf_memappend() directly unless it 54 | * checks the return code. Use printbuf_memappend_fast() instead. 55 | */ 56 | JSON_EXPORT int printbuf_memappend(struct printbuf *p, const char *buf, int size); 57 | 58 | #define printbuf_memappend_fast(p, bufptr, bufsize) \ 59 | do \ 60 | { \ 61 | if ((p->size - p->bpos) > bufsize) \ 62 | { \ 63 | memcpy(p->buf + p->bpos, (bufptr), bufsize); \ 64 | p->bpos += bufsize; \ 65 | p->buf[p->bpos] = '\0'; \ 66 | } \ 67 | else \ 68 | { \ 69 | printbuf_memappend(p, (bufptr), bufsize); \ 70 | } \ 71 | } while (0) 72 | 73 | #define printbuf_length(p) ((p)->bpos) 74 | 75 | /** 76 | * Results in a compile error if the argument is not a string literal. 77 | */ 78 | #define _printbuf_check_literal(mystr) ("" mystr) 79 | 80 | /** 81 | * This is an optimization wrapper around printbuf_memappend() that is useful 82 | * for appending string literals. Since the size of string constants is known 83 | * at compile time, using this macro can avoid a costly strlen() call. This is 84 | * especially helpful when a constant string must be appended many times. If 85 | * you got here because of a compilation error caused by passing something 86 | * other than a string literal, use printbuf_memappend_fast() in conjunction 87 | * with strlen(). 88 | * 89 | * See also: 90 | * printbuf_memappend_fast() 91 | * printbuf_memappend() 92 | * sprintbuf() 93 | */ 94 | #define printbuf_strappend(pb, str) \ 95 | printbuf_memappend((pb), _printbuf_check_literal(str), sizeof(str) - 1) 96 | 97 | /** 98 | * Set len bytes of the buffer to charvalue, starting at offset offset. 99 | * Similar to calling memset(x, charvalue, len); 100 | * 101 | * The memory allocated for the buffer is extended as necessary. 102 | * 103 | * If offset is -1, this starts at the end of the current data in the buffer. 104 | */ 105 | JSON_EXPORT int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len); 106 | 107 | /** 108 | * Formatted print to printbuf. 109 | * 110 | * This function is the most expensive of the available functions for appending 111 | * string data to a printbuf and should be used only where convenience is more 112 | * important than speed. Avoid using this function in high performance code or 113 | * tight loops; in these scenarios, consider using snprintf() with a static 114 | * buffer in conjunction with one of the printbuf_*append() functions. 115 | * 116 | * See also: 117 | * printbuf_memappend_fast() 118 | * printbuf_memappend() 119 | * printbuf_strappend() 120 | */ 121 | JSON_EXPORT int sprintbuf(struct printbuf *p, const char *msg, ...); 122 | 123 | JSON_EXPORT void printbuf_reset(struct printbuf *p); 124 | 125 | JSON_EXPORT void printbuf_free(struct printbuf *p); 126 | 127 | #ifdef __cplusplus 128 | } 129 | #endif 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /dependencies/include/json-c/random_seed.h: -------------------------------------------------------------------------------- 1 | /* 2 | * random_seed.h 3 | * 4 | * Copyright (c) 2013 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | /** 13 | * @file 14 | * @brief Do not use, json-c internal, may be changed or removed at any time. 15 | */ 16 | #ifndef seed_h 17 | #define seed_h 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | extern int json_c_get_random_seed(void); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /dependencies/include/json-c/snprintf_compat.h: -------------------------------------------------------------------------------- 1 | #ifndef __snprintf_compat_h 2 | #define __snprintf_compat_h 3 | 4 | /** 5 | * @file 6 | * @brief Do not use, json-c internal, may be changed or removed at any time. 7 | */ 8 | 9 | /* 10 | * Microsoft's _vsnprintf and _snprint don't always terminate 11 | * the string, so use wrappers that ensure that. 12 | */ 13 | 14 | #include 15 | 16 | #if !defined(HAVE_SNPRINTF) && (defined(_MSC_VER) || defined(__MINGW32__)) 17 | static int json_c_vsnprintf(char *str, size_t size, const char *format, va_list ap) 18 | { 19 | int ret; 20 | ret = _vsnprintf(str, size, format, ap); 21 | str[size - 1] = '\0'; 22 | return ret; 23 | } 24 | #define vsnprintf json_c_vsnprintf 25 | 26 | static int json_c_snprintf(char *str, size_t size, const char *format, ...) 27 | { 28 | va_list ap; 29 | int ret; 30 | va_start(ap, format); 31 | ret = json_c_vsnprintf(str, size, format, ap); 32 | va_end(ap); 33 | return ret; 34 | } 35 | #define snprintf json_c_snprintf 36 | 37 | #elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */ 38 | #error snprintf is required but was not found 39 | #endif /* !HAVE_SNPRINTF */ 40 | 41 | #endif /* __snprintf_compat_h */ 42 | -------------------------------------------------------------------------------- /dependencies/include/json-c/strdup_compat.h: -------------------------------------------------------------------------------- 1 | #ifndef __strdup_compat_h 2 | #define __strdup_compat_h 3 | 4 | /** 5 | * @file 6 | * @brief Do not use, json-c internal, may be changed or removed at any time. 7 | */ 8 | 9 | #if !defined(HAVE_STRDUP) && defined(_MSC_VER) 10 | /* MSC has the version as _strdup */ 11 | #define strdup _strdup 12 | #elif !defined(HAVE_STRDUP) 13 | #error You do not have strdup on your system. 14 | #endif /* HAVE_STRDUP */ 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /dependencies/include/json-c/strerror_override.h: -------------------------------------------------------------------------------- 1 | #ifndef _json_strerror_override_h_ 2 | #define _json_strerror_override_h_ 3 | 4 | /** 5 | * @file 6 | * @brief Do not use, json-c internal, may be changed or removed at any time. 7 | */ 8 | 9 | #include "config.h" 10 | #include 11 | 12 | #include "json_object.h" /* for JSON_EXPORT */ 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include 19 | 20 | JSON_EXPORT char *_json_c_strerror(int errno_in); 21 | 22 | #ifndef STRERROR_OVERRIDE_IMPL 23 | #define strerror _json_c_strerror 24 | #endif 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | 30 | #endif /* _json_strerror_override_h_ */ 31 | -------------------------------------------------------------------------------- /dependencies/include/json-c/vasprintf_compat.h: -------------------------------------------------------------------------------- 1 | #ifndef __vasprintf_compat_h 2 | #define __vasprintf_compat_h 3 | 4 | /** 5 | * @file 6 | * @brief Do not use, json-c internal, may be changed or removed at any time. 7 | */ 8 | 9 | #include "snprintf_compat.h" 10 | 11 | #ifndef _WIN32 12 | #include 13 | #endif /* !defined(_WIN32) */ 14 | #include 15 | #include 16 | 17 | #if !defined(HAVE_VASPRINTF) 18 | /* CAW: compliant version of vasprintf */ 19 | static int vasprintf(char **buf, const char *fmt, va_list ap) 20 | { 21 | #ifndef _WIN32 22 | static char _T_emptybuffer = '\0'; 23 | va_list ap2; 24 | #endif /* !defined(_WIN32) */ 25 | int chars; 26 | char *b; 27 | 28 | if (!buf) 29 | { 30 | return -1; 31 | } 32 | 33 | #ifdef _WIN32 34 | chars = _vscprintf(fmt, ap); 35 | #else /* !defined(_WIN32) */ 36 | /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite 37 | * our buffer like on some 64bit sun systems... but hey, it's time to move on 38 | */ 39 | va_copy(ap2, ap); 40 | chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap2); 41 | va_end(ap2); 42 | #endif /* defined(_WIN32) */ 43 | if (chars < 0 || (size_t)chars + 1 > SIZE_MAX / sizeof(char)) 44 | { 45 | return -1; 46 | } 47 | 48 | b = (char *)malloc(sizeof(char) * ((size_t)chars + 1)); 49 | if (!b) 50 | { 51 | return -1; 52 | } 53 | 54 | if ((chars = vsprintf(b, fmt, ap)) < 0) 55 | { 56 | free(b); 57 | } 58 | else 59 | { 60 | *buf = b; 61 | } 62 | 63 | return chars; 64 | } 65 | #endif /* !HAVE_VASPRINTF */ 66 | 67 | #endif /* __vasprintf_compat_h */ 68 | -------------------------------------------------------------------------------- /dependencies/include/ncursesw/eti.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2020 Thomas E. Dickey * 3 | * Copyright 1998-2002,2003 Free Software Foundation, Inc. * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a * 6 | * copy of this software and associated documentation files (the * 7 | * "Software"), to deal in the Software without restriction, including * 8 | * without limitation the rights to use, copy, modify, merge, publish, * 9 | * distribute, distribute with modifications, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so, subject to the following conditions: * 12 | * * 13 | * The above copyright notice and this permission notice shall be included * 14 | * in all copies or substantial portions of the Software. * 15 | * * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 | * * 24 | * Except as contained in this notice, the name(s) of the above copyright * 25 | * holders shall not be used in advertising or otherwise to promote the * 26 | * sale, use or other dealings in this Software without prior written * 27 | * authorization. * 28 | ****************************************************************************/ 29 | 30 | /**************************************************************************** 31 | * Author: Juergen Pfeifer, 1995,1997 * 32 | ****************************************************************************/ 33 | 34 | /* $Id: eti.h,v 1.9 2020/02/02 23:34:34 tom Exp $ */ 35 | 36 | #ifndef NCURSES_ETI_H_incl 37 | #define NCURSES_ETI_H_incl 1 38 | 39 | #define E_OK (0) 40 | #define E_SYSTEM_ERROR (-1) 41 | #define E_BAD_ARGUMENT (-2) 42 | #define E_POSTED (-3) 43 | #define E_CONNECTED (-4) 44 | #define E_BAD_STATE (-5) 45 | #define E_NO_ROOM (-6) 46 | #define E_NOT_POSTED (-7) 47 | #define E_UNKNOWN_COMMAND (-8) 48 | #define E_NO_MATCH (-9) 49 | #define E_NOT_SELECTABLE (-10) 50 | #define E_NOT_CONNECTED (-11) 51 | #define E_REQUEST_DENIED (-12) 52 | #define E_INVALID_FIELD (-13) 53 | #define E_CURRENT (-14) 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /dependencies/include/ncursesw/nc_tparm.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2018,2020 Thomas E. Dickey * 3 | * Copyright 2006-2012,2017 Free Software Foundation, Inc. * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a * 6 | * copy of this software and associated documentation files (the * 7 | * "Software"), to deal in the Software without restriction, including * 8 | * without limitation the rights to use, copy, modify, merge, publish, * 9 | * distribute, distribute with modifications, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so, subject to the following conditions: * 12 | * * 13 | * The above copyright notice and this permission notice shall be included * 14 | * in all copies or substantial portions of the Software. * 15 | * * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 | * * 24 | * Except as contained in this notice, the name(s) of the above copyright * 25 | * holders shall not be used in advertising or otherwise to promote the * 26 | * sale, use or other dealings in this Software without prior written * 27 | * authorization. * 28 | ****************************************************************************/ 29 | 30 | /**************************************************************************** 31 | * Author: Thomas E. Dickey 2006 * 32 | ****************************************************************************/ 33 | 34 | /* $Id: nc_tparm.h,v 1.11 2020/05/27 23:33:31 tom Exp $ */ 35 | 36 | #ifndef NC_TPARM_included 37 | #define NC_TPARM_included 1 38 | 39 | #include 40 | #include 41 | 42 | /* 43 | * Cast parameters past the formatting-string for tparm() to match the 44 | * assumption of the varargs code. 45 | */ 46 | #ifndef TPARM_ARG 47 | #ifdef NCURSES_TPARM_ARG 48 | #define TPARM_ARG NCURSES_TPARM_ARG 49 | #else 50 | #define TPARM_ARG long 51 | #endif 52 | #endif /* TPARAM_ARG */ 53 | 54 | #define TPARM_N(n) (TPARM_ARG)(n) 55 | 56 | #define TPARM_9(a,b,c,d,e,f,g,h,i,j) tparm(a,TPARM_N(b),TPARM_N(c),TPARM_N(d),TPARM_N(e),TPARM_N(f),TPARM_N(g),TPARM_N(h),TPARM_N(i),TPARM_N(j)) 57 | 58 | #if NCURSES_TPARM_VARARGS 59 | #define TPARM_8(a,b,c,d,e,f,g,h,i) tparm(a,TPARM_N(b),TPARM_N(c),TPARM_N(d),TPARM_N(e),TPARM_N(f),TPARM_N(g),TPARM_N(h),TPARM_N(i)) 60 | #define TPARM_7(a,b,c,d,e,f,g,h) tparm(a,TPARM_N(b),TPARM_N(c),TPARM_N(d),TPARM_N(e),TPARM_N(f),TPARM_N(g),TPARM_N(h)) 61 | #define TPARM_6(a,b,c,d,e,f,g) tparm(a,TPARM_N(b),TPARM_N(c),TPARM_N(d),TPARM_N(e),TPARM_N(f),TPARM_N(g)) 62 | #define TPARM_5(a,b,c,d,e,f) tparm(a,TPARM_N(b),TPARM_N(c),TPARM_N(d),TPARM_N(e),TPARM_N(f)) 63 | #define TPARM_4(a,b,c,d,e) tparm(a,TPARM_N(b),TPARM_N(c),TPARM_N(d),TPARM_N(e)) 64 | #define TPARM_3(a,b,c,d) tparm(a,TPARM_N(b),TPARM_N(c),TPARM_N(d)) 65 | #define TPARM_2(a,b,c) tparm(a,TPARM_N(b),TPARM_N(c)) 66 | #define TPARM_1(a,b) tparm(a,TPARM_N(b)) 67 | #define TPARM_0(a) tparm(a) 68 | #else 69 | #define TPARM_8(a,b,c,d,e,f,g,h,i) TPARM_9(a,b,c,d,e,f,g,h,i,0) 70 | #define TPARM_7(a,b,c,d,e,f,g,h) TPARM_8(a,b,c,d,e,f,g,h,0) 71 | #define TPARM_6(a,b,c,d,e,f,g) TPARM_7(a,b,c,d,e,f,g,0) 72 | #define TPARM_5(a,b,c,d,e,f) TPARM_6(a,b,c,d,e,f,0) 73 | #define TPARM_4(a,b,c,d,e) TPARM_5(a,b,c,d,e,0) 74 | #define TPARM_3(a,b,c,d) TPARM_4(a,b,c,d,0) 75 | #define TPARM_2(a,b,c) TPARM_3(a,b,c,0) 76 | #define TPARM_1(a,b) TPARM_2(a,b,0) 77 | #define TPARM_0(a) TPARM_1(a,0) 78 | #endif 79 | 80 | #ifdef NCURSES_INTERNALS 81 | #define TIPARM_1(s,a) _nc_tiparm(1,s,a) 82 | #define TIPARM_2(s,a,b) _nc_tiparm(2,s,a,b) 83 | #define TIPARM_3(s,a,b,c) _nc_tiparm(3,s,a,b,c) 84 | #define TIPARM_4(s,a,b,c,d) _nc_tiparm(4,s,a,b,c,d) 85 | #define TIPARM_5(s,a,b,c,d,e) _nc_tiparm(5,s,a,b,c,d,e) 86 | #define TIPARM_6(s,a,b,c,d,e,f) _nc_tiparm(6,s,a,b,c,d,e,f) 87 | #define TIPARM_7(s,a,b,c,d,e,f,g) _nc_tiparm(7,s,a,b,c,d,e,f,g) 88 | #define TIPARM_8(s,a,b,c,d,e,f,g,h) _nc_tiparm(8,s,a,b,c,d,e,f,g,h) 89 | #define TIPARM_9(s,a,b,c,d,e,f,g,h,i) _nc_tiparm(9,s,a,b,c,d,e,f,g,h,i) 90 | #endif 91 | 92 | #endif /* NC_TPARM_included */ 93 | -------------------------------------------------------------------------------- /dependencies/include/ncursesw/ncurses_dll.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2018,2020 Thomas E. Dickey * 3 | * Copyright 2009,2014 Free Software Foundation, Inc. * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a * 6 | * copy of this software and associated documentation files (the * 7 | * "Software"), to deal in the Software without restriction, including * 8 | * without limitation the rights to use, copy, modify, merge, publish, * 9 | * distribute, distribute with modifications, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so, subject to the following conditions: * 12 | * * 13 | * The above copyright notice and this permission notice shall be included * 14 | * in all copies or substantial portions of the Software. * 15 | * * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 | * * 24 | * Except as contained in this notice, the name(s) of the above copyright * 25 | * holders shall not be used in advertising or otherwise to promote the * 26 | * sale, use or other dealings in this Software without prior written * 27 | * authorization. * 28 | ****************************************************************************/ 29 | /* $Id: ncurses_dll.h.in,v 1.17 2020/09/05 17:58:47 juergen Exp $ */ 30 | 31 | #ifndef NCURSES_DLL_H_incl 32 | #define NCURSES_DLL_H_incl 1 33 | 34 | /* 35 | * MinGW gcc (unlike MSYS2 and Cygwin) should define _WIN32 and possibly _WIN64. 36 | */ 37 | #if defined(__MINGW64__) 38 | 39 | #ifndef _WIN64 40 | #define _WIN64 1 41 | #endif 42 | 43 | #elif defined(__MINGW32__) 44 | 45 | #ifndef _WIN32 46 | #define _WIN32 1 47 | #endif 48 | 49 | /* 2014-08-02 workaround for broken MinGW compiler. 50 | * Oddly, only TRACE is mapped to trace - the other -D's are okay. 51 | * suggest TDM as an alternative. 52 | */ 53 | #if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) 54 | 55 | #ifdef trace 56 | #undef trace 57 | #define TRACE 58 | #endif 59 | 60 | #endif /* broken compiler */ 61 | 62 | #endif /* MingW */ 63 | 64 | /* 65 | * For reentrant code, we map the various global variables into SCREEN by 66 | * using functions to access them. 67 | */ 68 | #define NCURSES_PUBLIC_VAR(name) _nc_##name 69 | 70 | #if defined(BUILDING_NCURSES) 71 | # define NCURSES_IMPEXP NCURSES_EXPORT_GENERAL_EXPORT 72 | #else 73 | # define NCURSES_IMPEXP NCURSES_EXPORT_GENERAL_IMPORT 74 | #endif 75 | 76 | #define NCURSES_WRAPPED_VAR(type,name) extern NCURSES_IMPEXP type NCURSES_PUBLIC_VAR(name)(void) 77 | 78 | #define NCURSES_EXPORT(type) NCURSES_IMPEXP type NCURSES_API 79 | #define NCURSES_EXPORT_VAR(type) NCURSES_IMPEXP type 80 | 81 | /* 82 | * These symbols hide dllimport/dllexport, for compilers which care about it. 83 | */ 84 | #if defined(__CYGWIN__) || (defined(_WIN32) || defined(_WIN64)) 85 | # if defined(NCURSES_STATIC) /* "static" here only implies "not-a-DLL" */ 86 | # define NCURSES_EXPORT_GENERAL_IMPORT 87 | # define NCURSES_EXPORT_GENERAL_EXPORT 88 | # else 89 | # define NCURSES_EXPORT_GENERAL_IMPORT __declspec(dllimport) 90 | # define NCURSES_EXPORT_GENERAL_EXPORT __declspec(dllexport) 91 | # endif 92 | # define NCURSES_API __cdecl 93 | #else 94 | # define NCURSES_EXPORT_GENERAL_IMPORT 95 | # define NCURSES_EXPORT_GENERAL_EXPORT 96 | # define NCURSES_API /* FIXME: __attribute__ ((cdecl)) is only available on x86 */ 97 | #endif 98 | 99 | #endif /* NCURSES_DLL_H_incl */ 100 | -------------------------------------------------------------------------------- /dependencies/include/ncursesw/panel.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2020 Thomas E. Dickey * 3 | * Copyright 1998-2009,2017 Free Software Foundation, Inc. * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a * 6 | * copy of this software and associated documentation files (the * 7 | * "Software"), to deal in the Software without restriction, including * 8 | * without limitation the rights to use, copy, modify, merge, publish, * 9 | * distribute, distribute with modifications, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so, subject to the following conditions: * 12 | * * 13 | * The above copyright notice and this permission notice shall be included * 14 | * in all copies or substantial portions of the Software. * 15 | * * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 | * * 24 | * Except as contained in this notice, the name(s) of the above copyright * 25 | * holders shall not be used in advertising or otherwise to promote the * 26 | * sale, use or other dealings in this Software without prior written * 27 | * authorization. * 28 | ****************************************************************************/ 29 | 30 | /**************************************************************************** 31 | * Author: Zeyd M. Ben-Halim 1995 * 32 | * and: Eric S. Raymond * 33 | * and: Juergen Pfeifer 1996-1999,2008 * 34 | ****************************************************************************/ 35 | 36 | /* $Id: panel.h,v 1.14 2020/07/04 20:38:43 tom Exp $ */ 37 | 38 | /* panel.h -- interface file for panels library */ 39 | 40 | #ifndef NCURSES_PANEL_H_incl 41 | #define NCURSES_PANEL_H_incl 1 42 | 43 | #include 44 | 45 | typedef struct panel 46 | #if !NCURSES_OPAQUE_PANEL 47 | { 48 | WINDOW *win; 49 | struct panel *below; 50 | struct panel *above; 51 | NCURSES_CONST void *user; 52 | } 53 | #endif /* !NCURSES_OPAQUE_PANEL */ 54 | PANEL; 55 | 56 | #if defined(__cplusplus) 57 | extern "C" { 58 | #endif 59 | 60 | #if defined(BUILDING_PANEL) 61 | # define PANEL_IMPEXP NCURSES_EXPORT_GENERAL_EXPORT 62 | #else 63 | # define PANEL_IMPEXP NCURSES_EXPORT_GENERAL_IMPORT 64 | #endif 65 | 66 | #define PANEL_WRAPPED_VAR(type,name) extern PANEL_IMPEXP type NCURSES_PUBLIC_VAR(name)(void) 67 | 68 | #define PANEL_EXPORT(type) PANEL_IMPEXP type NCURSES_API 69 | #define PANEL_EXPORT_VAR(type) PANEL_IMPEXP type 70 | 71 | extern PANEL_EXPORT(WINDOW*) panel_window (const PANEL *); 72 | extern PANEL_EXPORT(void) update_panels (void); 73 | extern PANEL_EXPORT(int) hide_panel (PANEL *); 74 | extern PANEL_EXPORT(int) show_panel (PANEL *); 75 | extern PANEL_EXPORT(int) del_panel (PANEL *); 76 | extern PANEL_EXPORT(int) top_panel (PANEL *); 77 | extern PANEL_EXPORT(int) bottom_panel (PANEL *); 78 | extern PANEL_EXPORT(PANEL*) new_panel (WINDOW *); 79 | extern PANEL_EXPORT(PANEL*) panel_above (const PANEL *); 80 | extern PANEL_EXPORT(PANEL*) panel_below (const PANEL *); 81 | extern PANEL_EXPORT(int) set_panel_userptr (PANEL *, NCURSES_CONST void *); 82 | extern PANEL_EXPORT(NCURSES_CONST void*) panel_userptr (const PANEL *); 83 | extern PANEL_EXPORT(int) move_panel (PANEL *, int, int); 84 | extern PANEL_EXPORT(int) replace_panel (PANEL *,WINDOW *); 85 | extern PANEL_EXPORT(int) panel_hidden (const PANEL *); 86 | 87 | #if NCURSES_SP_FUNCS 88 | extern PANEL_EXPORT(PANEL *) ground_panel(SCREEN *); 89 | extern PANEL_EXPORT(PANEL *) ceiling_panel(SCREEN *); 90 | 91 | extern PANEL_EXPORT(void) NCURSES_SP_NAME(update_panels) (SCREEN*); 92 | #endif 93 | 94 | #if defined(__cplusplus) 95 | } 96 | #endif 97 | 98 | #endif /* NCURSES_PANEL_H_incl */ 99 | 100 | /* end of panel.h */ 101 | -------------------------------------------------------------------------------- /dependencies/include/ncursesw/termcap.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2018-2020,2021 Thomas E. Dickey * 3 | * Copyright 1998-2000,2001 Free Software Foundation, Inc. * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a * 6 | * copy of this software and associated documentation files (the * 7 | * "Software"), to deal in the Software without restriction, including * 8 | * without limitation the rights to use, copy, modify, merge, publish, * 9 | * distribute, distribute with modifications, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so, subject to the following conditions: * 12 | * * 13 | * The above copyright notice and this permission notice shall be included * 14 | * in all copies or substantial portions of the Software. * 15 | * * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 | * * 24 | * Except as contained in this notice, the name(s) of the above copyright * 25 | * holders shall not be used in advertising or otherwise to promote the * 26 | * sale, use or other dealings in this Software without prior written * 27 | * authorization. * 28 | ****************************************************************************/ 29 | 30 | /**************************************************************************** 31 | * Author: Zeyd M. Ben-Halim 1992,1995 * 32 | * and: Eric S. Raymond * 33 | ****************************************************************************/ 34 | 35 | /* $Id: termcap.h.in,v 1.20 2021/06/17 21:26:02 tom Exp $ */ 36 | 37 | #ifndef NCURSES_TERMCAP_H_incl 38 | #define NCURSES_TERMCAP_H_incl 1 39 | 40 | #undef NCURSES_VERSION 41 | #define NCURSES_VERSION "6.4" 42 | 43 | #include 44 | 45 | #ifdef __cplusplus 46 | extern "C" 47 | { 48 | #endif /* __cplusplus */ 49 | 50 | #include 51 | 52 | #undef NCURSES_OSPEED 53 | #define NCURSES_OSPEED short 54 | 55 | extern NCURSES_EXPORT_VAR(char) PC; 56 | extern NCURSES_EXPORT_VAR(char *) UP; 57 | extern NCURSES_EXPORT_VAR(char *) BC; 58 | extern NCURSES_EXPORT_VAR(NCURSES_OSPEED) ospeed; 59 | 60 | #if !defined(NCURSES_TERM_H_incl) 61 | extern NCURSES_EXPORT(char *) tgetstr (const char *, char **); 62 | extern NCURSES_EXPORT(char *) tgoto (const char *, int, int); 63 | extern NCURSES_EXPORT(int) tgetent (char *, const char *); 64 | extern NCURSES_EXPORT(int) tgetflag (const char *); 65 | extern NCURSES_EXPORT(int) tgetnum (const char *); 66 | extern NCURSES_EXPORT(int) tputs (const char *, int, int (*)(int)); 67 | #endif 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif /* NCURSES_TERMCAP_H_incl */ 74 | -------------------------------------------------------------------------------- /dependencies/include/ncursesw/unctrl.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2020 Thomas E. Dickey * 3 | * Copyright 1998-2001,2009 Free Software Foundation, Inc. * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a * 6 | * copy of this software and associated documentation files (the * 7 | * "Software"), to deal in the Software without restriction, including * 8 | * without limitation the rights to use, copy, modify, merge, publish, * 9 | * distribute, distribute with modifications, sublicense, and/or sell * 10 | * copies of the Software, and to permit persons to whom the Software is * 11 | * furnished to do so, subject to the following conditions: * 12 | * * 13 | * The above copyright notice and this permission notice shall be included * 14 | * in all copies or substantial portions of the Software. * 15 | * * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 | * * 24 | * Except as contained in this notice, the name(s) of the above copyright * 25 | * holders shall not be used in advertising or otherwise to promote the * 26 | * sale, use or other dealings in this Software without prior written * 27 | * authorization. * 28 | ****************************************************************************/ 29 | 30 | /**************************************************************************** 31 | * Author: Zeyd M. Ben-Halim 1992,1995 * 32 | * and: Eric S. Raymond * 33 | ****************************************************************************/ 34 | 35 | /* 36 | * unctrl.h 37 | * 38 | * Display a printable version of a control character. 39 | * Control characters are displayed in caret notation (^x), DELETE is displayed 40 | * as ^?. Printable characters are displayed as is. 41 | */ 42 | 43 | /* $Id: unctrl.h.in,v 1.12 2020/02/02 23:34:34 tom Exp $ */ 44 | 45 | #ifndef NCURSES_UNCTRL_H_incl 46 | #define NCURSES_UNCTRL_H_incl 1 47 | 48 | #undef NCURSES_VERSION 49 | #define NCURSES_VERSION "6.4" 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | #include 56 | 57 | #undef unctrl 58 | NCURSES_EXPORT(NCURSES_CONST char *) unctrl (chtype); 59 | 60 | #if 1 61 | NCURSES_EXPORT(NCURSES_CONST char *) NCURSES_SP_NAME(unctrl) (SCREEN*, chtype); 62 | #endif 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | 68 | #endif /* NCURSES_UNCTRL_H_incl */ 69 | -------------------------------------------------------------------------------- /dependencies/kat/hashtable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2019 Davidson Francis 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef HASHTABLE_H 26 | #define HASHTABLE_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | /** 33 | * @brief Hashtable initial size. 34 | */ 35 | #define HASHTABLE_DEFAULT_SIZE 16 36 | 37 | /** 38 | * @brief Enable additional debug data, like collision counting. 39 | */ 40 | #define HASHTABLE_DEBUG 1 41 | 42 | /** 43 | * @brief Hashtable linked list structure. 44 | */ 45 | struct list 46 | { 47 | void *key; /* Entry key. */ 48 | void *value; /* Entry value. */ 49 | uint64_t hash; /* Entry hash. */ 50 | struct list *next; /* Entry next list. */ 51 | }; 52 | 53 | /** 54 | * @brief Hashtable structure. 55 | */ 56 | struct hashtable 57 | { 58 | struct list **bucket; /* Bucket list. */ 59 | size_t capacity; /* Current capacity. */ 60 | size_t elements; /* Current elements. */ 61 | ssize_t key_size; /* Hash key size. */ 62 | 63 | #if HASHTABLE_DEBUG 64 | size_t collisions; /* Collisions count. */ 65 | #endif 66 | 67 | /* Function pointers. */ 68 | uint64_t (*hash) (const void *key, size_t size); 69 | int (*cmp) (const void *key1, const void *key2); 70 | }; 71 | 72 | /* ==================== External functions ==================== */ 73 | extern int hashtable_init( 74 | struct hashtable **ht, 75 | void (*setup_algorithm)(struct hashtable **ht) 76 | ); 77 | 78 | extern int hashtable_finish(struct hashtable **ht, int dealloc); 79 | extern int hashtable_add(struct hashtable **ht, void *key, void *value); 80 | extern void* hashtable_get(struct hashtable **ht, void *key); 81 | extern void hashtable_print_stats(struct hashtable **ht); 82 | 83 | /* ==================== Hash functions ==================== */ 84 | extern int hashtable_cmp_ptr(const void *key1, const void *key2); 85 | 86 | /* sdbm. */ 87 | extern void hashtable_sdbm_setup(struct hashtable **ht); 88 | extern uint64_t hashtable_sdbm(const void *key, size_t size); 89 | 90 | /* Splitmix64. */ 91 | extern void hashtable_splitmix64_setup(struct hashtable **ht); 92 | extern uint64_t hashtable_splitmix64_hash(const void *key, size_t size); 93 | 94 | /* MurMur3 Hash. */ 95 | extern void hashtable_MurMur3_setup(struct hashtable **ht); 96 | extern uint64_t hashtable_MurMur3_hash(const void *key, size_t size); 97 | 98 | #endif /* HASHTABLE_H */ 99 | -------------------------------------------------------------------------------- /dependencies/libs/libcapstone-ios.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/dependencies/libs/libcapstone-ios.a -------------------------------------------------------------------------------- /dependencies/libs/libcapstone-mac.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/dependencies/libs/libcapstone-mac.a -------------------------------------------------------------------------------- /dependencies/libs/libjson-c-ios.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/dependencies/libs/libjson-c-ios.a -------------------------------------------------------------------------------- /dependencies/libs/libjson-c-mac.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/dependencies/libs/libjson-c-mac.a -------------------------------------------------------------------------------- /dependencies/libs/libncursesw-ios.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/dependencies/libs/libncursesw-ios.a -------------------------------------------------------------------------------- /imgs/TRACER_ARG_FORMAT_DESCRIPTIVE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/imgs/TRACER_ARG_FORMAT_DESCRIPTIVE.png -------------------------------------------------------------------------------- /imgs/TRACER_ARG_FORMAT_EXCLUDE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/imgs/TRACER_ARG_FORMAT_EXCLUDE.png -------------------------------------------------------------------------------- /imgs/banner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/imgs/banner.gif -------------------------------------------------------------------------------- /imgs/thread-output-interweaving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/imgs/thread-output-interweaving.png -------------------------------------------------------------------------------- /imgs/tui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lessica/objsee-ios/39d33015357b552be37ab17061f66c6acc2eab10/imgs/tui.png -------------------------------------------------------------------------------- /layout/usr/lib/libobjsee.dylib: -------------------------------------------------------------------------------- 1 | ../../Library/Frameworks/objsee.framework/objsee -------------------------------------------------------------------------------- /objsee.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/libobjsee/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | objsee 9 | CFBundleIdentifier 10 | com.ethanarbuckle.objsee-framework 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | FMWK 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/libobjsee/config/config_decode.h: -------------------------------------------------------------------------------- 1 | // 2 | // config_decode.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/1/24. 6 | // 7 | 8 | #ifndef CONFIG_DECODE_H 9 | #define CONFIG_DECODE_H 10 | 11 | #include "tracer_internal.h" 12 | 13 | #define CONFIG_ENV_VAR "OBJSEE_CONFIG" 14 | 15 | /** 16 | * @brief Decode a tracer configuration from an encoded string 17 | * 18 | * @param config_str Base64 encoded json string representing the configuration 19 | * @param config The output configuration 20 | * @return tracer_result_t TRACER_SUCCESS on success, or an error code on failure 21 | */ 22 | tracer_result_t decode_tracer_config(const char *config_str, tracer_config_t *config); 23 | 24 | 25 | /** 26 | * @brief Build a human readable description from a tracer configuration 27 | * @param config The configuration to describe 28 | * @return const char* A human readable description of the configuration. This string must be freed by the caller. 29 | */ 30 | const char *copy_human_readable_config(tracer_config_t config); 31 | 32 | #endif // CONFIG_DECODE_H 33 | -------------------------------------------------------------------------------- /src/libobjsee/config/config_encode.c: -------------------------------------------------------------------------------- 1 | // 2 | // config_encode.c 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/1/24. 6 | // 7 | 8 | #include 9 | #include 10 | #include "config_encode.h" 11 | 12 | static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 13 | 14 | static char *base64_encode(const unsigned char *input, size_t length) { 15 | size_t output_len = 4 * ((length + 2) / 3); 16 | char *encoded = malloc(output_len + 1); 17 | if (encoded == NULL) { 18 | return NULL; 19 | } 20 | 21 | size_t i = 0; 22 | size_t j = 0; 23 | size_t remaining = length; 24 | while (remaining >= 3) { 25 | encoded[j++] = base64_table[input[i] >> 2]; 26 | encoded[j++] = base64_table[((input[i] & 0x03) << 4) | (input[i + 1] >> 4)]; 27 | encoded[j++] = base64_table[((input[i + 1] & 0x0f) << 2) | (input[i + 2] >> 6)]; 28 | encoded[j++] = base64_table[input[i + 2] & 0x3f]; 29 | i += 3; 30 | remaining -= 3; 31 | } 32 | 33 | if (remaining) { 34 | encoded[j++] = base64_table[input[i] >> 2]; 35 | if (remaining == 1) { 36 | encoded[j++] = base64_table[(input[i] & 0x03) << 4]; 37 | encoded[j++] = '='; 38 | } 39 | else { 40 | encoded[j++] = base64_table[((input[i] & 0x03) << 4) | (input[i + 1] >> 4)]; 41 | encoded[j++] = base64_table[(input[i + 1] & 0x0f) << 2]; 42 | } 43 | encoded[j++] = '='; 44 | } 45 | 46 | encoded[j] = '\0'; 47 | return encoded; 48 | } 49 | 50 | tracer_result_t encode_tracer_config(tracer_config_t *config, char **out_str) { 51 | if (config == NULL || out_str == NULL) { 52 | return TRACER_ERROR_INVALID_ARGUMENT; 53 | } 54 | 55 | json_object *root = json_object_new_object(); 56 | if (root == NULL) { 57 | return TRACER_ERROR_MEMORY; 58 | } 59 | 60 | if (config->transport_config.host) { 61 | json_object_object_add(root, "host", json_object_new_string(config->transport_config.host)); 62 | } 63 | if (config->transport_config.port) { 64 | json_object_object_add(root, "port", json_object_new_int(config->transport_config.port)); 65 | } 66 | if (config->transport_config.file_path) { 67 | json_object_object_add(root, "file", json_object_new_string(config->transport_config.file_path)); 68 | } 69 | json_object_object_add(root, "transport", json_object_new_int(config->transport)); 70 | 71 | json_object *format = json_object_new_object(); 72 | if (format == NULL) { 73 | json_object_put(root); 74 | return TRACER_ERROR_MEMORY; 75 | } 76 | 77 | json_object_object_add(format, "include_formatted_trace", json_object_new_boolean(config->format.include_formatted_trace)); 78 | json_object_object_add(format, "include_event_json", json_object_new_boolean(config->format.include_event_json)); 79 | json_object_object_add(format, "output_as_json", json_object_new_boolean(config->format.output_as_json)); 80 | json_object_object_add(format, "include_colors", json_object_new_boolean(config->format.include_colors)); 81 | json_object_object_add(format, "include_thread_id", json_object_new_boolean(config->format.include_thread_id)); 82 | json_object_object_add(format, "include_indents", json_object_new_boolean(config->format.include_indents)); 83 | json_object_object_add(format, "indent_char", json_object_new_string(config->format.indent_char)); 84 | json_object_object_add(format, "include_indent_separators", json_object_new_boolean(config->format.include_indent_separators)); 85 | json_object_object_add(format, "indent_separator_char", json_object_new_string(config->format.indent_separator_char)); 86 | json_object_object_add(format, "variable_separator_spacing", json_object_new_boolean(config->format.variable_separator_spacing)); 87 | json_object_object_add(format, "static_separator_spacing", json_object_new_int(config->format.static_separator_spacing)); 88 | json_object_object_add(format, "include_newline_in_formatted_trace", json_object_new_boolean(config->format.include_newline_in_formatted_trace)); 89 | json_object_object_add(format, "arg_format", json_object_new_int(config->format.args)); 90 | json_object_object_add(root, "format", format); 91 | 92 | if (config->filter_count > 0) { 93 | json_object *filters_array = json_object_new_array(); 94 | if (filters_array == NULL) { 95 | json_object_put(root); 96 | return TRACER_ERROR_MEMORY; 97 | } 98 | 99 | for (size_t i = 0; i < config->filter_count; i++) { 100 | json_object *filter = json_object_new_object(); 101 | if (filter == NULL) { 102 | continue; 103 | } 104 | 105 | if (config->filters[i].class_pattern) { 106 | json_object_object_add(filter, "class", json_object_new_string(config->filters[i].class_pattern)); 107 | } 108 | if (config->filters[i].method_pattern) { 109 | json_object_object_add(filter, "method", json_object_new_string(config->filters[i].method_pattern)); 110 | } 111 | if (config->filters[i].image_pattern) { 112 | json_object_object_add(filter, "image", json_object_new_string(config->filters[i].image_pattern)); 113 | } 114 | 115 | json_object_object_add(filter, "exclude", json_object_new_boolean(config->filters[i].exclude)); 116 | json_object_array_add(filters_array, filter); 117 | } 118 | 119 | json_object_object_add(root, "filters", filters_array); 120 | } 121 | 122 | const char *json_str = json_object_to_json_string(root); 123 | if (json_str == NULL) { 124 | json_object_put(root); 125 | return TRACER_ERROR_MEMORY; 126 | } 127 | 128 | *out_str = base64_encode((const unsigned char *)json_str, strlen(json_str)); 129 | 130 | json_object_put(root); 131 | return *out_str ? TRACER_SUCCESS : TRACER_ERROR_INVALID_ARGUMENT; 132 | } 133 | -------------------------------------------------------------------------------- /src/libobjsee/config/config_encode.h: -------------------------------------------------------------------------------- 1 | // 2 | // config_encode.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/1/24. 6 | // 7 | 8 | #ifndef CONFIG_ENCODE_H 9 | #define CONFIG_ENCODE_H 10 | 11 | #include "tracer.h" 12 | 13 | /** 14 | * @brief Serialize a tracer configuration into a base64 encoded string 15 | * 16 | * @param config The configuration to encode 17 | * @param out_str The output string 18 | * @return tracer_result_t 19 | */ 20 | tracer_result_t encode_tracer_config(tracer_config_t *config, char **out_str); 21 | 22 | #endif // CONFIG_ENCODE_H 23 | -------------------------------------------------------------------------------- /src/libobjsee/formatting/color_utils.c: -------------------------------------------------------------------------------- 1 | // 2 | // color_utils.c 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/1/24. 6 | // 7 | 8 | 9 | #include "tracer_internal.h" 10 | #include "color_utils.h" 11 | 12 | uint8_t get_consistent_color(const char *str, uint8_t start, uint16_t range) { 13 | if (str == NULL) { 14 | return start; 15 | } 16 | uint32_t hash = fnv1a_hash(str); 17 | return start + (hash % range); 18 | } 19 | -------------------------------------------------------------------------------- /src/libobjsee/formatting/color_utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // color_utils.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/1/24. 6 | // 7 | 8 | 9 | #ifndef COLOR_UTILS_H 10 | #define COLOR_UTILS_H 11 | 12 | #include 13 | 14 | #define COLOR_THREAD_START 31 15 | #define COLOR_THREAD_END 40 16 | #define COLOR_DEPTH_START 244 17 | #define COLOR_DEPTH_END 255 18 | #define COLOR_CLASS_START 25 19 | #define COLOR_CLASS_RANGE 108 20 | #define COLOR_METHOD_START 39 21 | #define COLOR_METHOD_RANGE 150 22 | 23 | #define COLOR_RESET "\x1b[0m" 24 | 25 | uint8_t get_consistent_color(const char *str, uint8_t start, uint16_t range); 26 | 27 | #endif // COLOR_UTILS_H 28 | -------------------------------------------------------------------------------- /src/libobjsee/formatting/format.h: -------------------------------------------------------------------------------- 1 | // 2 | // format.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 11/30/24. 6 | // 7 | 8 | #ifndef TRACER_FORMAT_H 9 | #define TRACER_FORMAT_H 10 | 11 | #include "tracer_internal.h" 12 | 13 | /** 14 | * @brief Build a JSON string representation of a trace event. This may include a formatted output string 15 | * 16 | * @param tracer The tracer instance 17 | * @param event The event to build a JSON string for 18 | * @return A JSON string representing the event 19 | */ 20 | const char *build_json_event_str(const tracer_t *tracer, const tracer_event_t *event); 21 | 22 | 23 | /** 24 | * @brief Format a trace event according to the configured format type (indented, with colors, etc) 25 | * 26 | * @param event The event to format 27 | * @param format The format options to use for formatting 28 | * @return A formatted string representing the event 29 | */ 30 | char *build_formatted_event_str(const tracer_event_t *event, tracer_format_options_t format); 31 | 32 | 33 | #endif // TRACER_FORMAT_H 34 | -------------------------------------------------------------------------------- /src/libobjsee/injection/loader.m: -------------------------------------------------------------------------------- 1 | // 2 | // loader.c 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/1/24. 6 | // 7 | 8 | #include 9 | #include 10 | #include "config_decode.h" 11 | 12 | OBJC_EXPORT void objsee_main(const char *encoded_config_string); 13 | 14 | // If enabled, delays the tracer's activation by 1 second to reduce early-injection crashes. 15 | // Some processes may crash if objsee_main() runs too early in launch (e.g., before critical 16 | // classes or subsystems are realized). 17 | // Disable this if early instrumentation is required and the target process tolerates it 18 | #define DELAY_INJECTION 1 19 | 20 | #if DELAY_INJECTION 21 | #define DELAY_WRAPPED(block) \ 22 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), block) 23 | #else 24 | #define DELAY_WRAPPED(block) block() 25 | #endif 26 | 27 | // Problems arise when the tracer is activated too early in the process launch, when some classes 28 | // may still be unrealized. To mitigate this, an objc +load method is used to initialize tracing. 29 | // The runtime is likely to be closer to "fully loaded" at this point compared to when constructor 30 | // functions are fired 31 | @interface RuntimeEntryShim : NSObject 32 | @end 33 | 34 | @implementation RuntimeEntryShim 35 | 36 | + (void)load { 37 | os_log(OS_LOG_DEFAULT, "objsee loaded"); 38 | 39 | // The cli tool provides the configuration for the tracer via an environment variable 40 | const char *encoded_config_string = getenv(CONFIG_ENV_VAR); 41 | if (encoded_config_string) { 42 | DELAY_WRAPPED(^{ 43 | objsee_main(encoded_config_string); 44 | }); 45 | } 46 | } 47 | 48 | @end 49 | 50 | void objsee_main(const char *encoded_config_string) { 51 | 52 | tracer_config_t config; 53 | config.came_from_envvar = false; 54 | 55 | if (encoded_config_string) { 56 | if (decode_tracer_config(encoded_config_string, &config) != TRACER_SUCCESS) { 57 | os_log(OS_LOG_DEFAULT, "Failed to decode tracer configuration"); 58 | return; 59 | } 60 | 61 | const char *config_description = copy_human_readable_config(config); 62 | if (config_description == NULL) { 63 | os_log(OS_LOG_DEFAULT, "Failed to encode config description"); 64 | return; 65 | } 66 | 67 | os_log(OS_LOG_DEFAULT, "Using config: %{PUBLIC}s", config_description); 68 | free((void *)config_description); 69 | config.came_from_envvar = true; 70 | } 71 | else { 72 | os_log(OS_LOG_DEFAULT, "No config provided, using defaults"); 73 | config = (tracer_config_t) { 74 | .transport = TRACER_TRANSPORT_SOCKET 75 | }; 76 | 77 | config.format = (tracer_format_options_t) { 78 | .include_colors = true, 79 | .include_formatted_trace = true, 80 | .include_event_json = false, 81 | .output_as_json = false, 82 | .include_thread_id = false, 83 | .include_indents = true, 84 | .indent_char = " ", 85 | .include_indent_separators = true, 86 | .indent_separator_char = "|", 87 | .variable_separator_spacing = false, 88 | .static_separator_spacing = 2, 89 | .include_newline_in_formatted_trace = false, 90 | .args = TRACER_ARG_FORMAT_CLASS, 91 | }; 92 | } 93 | 94 | tracer_error_t *error = NULL; 95 | tracer_t *tracer = tracer_create_with_config(config, &error); 96 | if (tracer == NULL) { 97 | os_log(OS_LOG_DEFAULT, "Failed to create tracer: %s", error->message); 98 | free_error(error); 99 | return; 100 | } 101 | 102 | if (config.came_from_envvar == false) { 103 | if (config.transport_config.host && config.transport_config.port) { 104 | tracer_set_output_socket(tracer, config.transport_config.host, config.transport_config.port); 105 | } 106 | else if (config.transport_config.file_path) { 107 | tracer_set_output_file(tracer, config.transport_config.file_path); 108 | } 109 | else { 110 | tracer_set_output_stdout(tracer); 111 | } 112 | } 113 | 114 | for (size_t i = 0; i < config.filter_count; i++) { 115 | tracer_add_filter(tracer, &config.filters[i]); 116 | } 117 | 118 | 119 | tracer_result_t ret = -1; 120 | for (int attempt = 0; attempt < 3; attempt++) { 121 | if ((ret = tracer_start(tracer)) == TRACER_SUCCESS) { 122 | os_log(OS_LOG_DEFAULT, "Tracer started"); 123 | break; 124 | } 125 | else { 126 | os_log(OS_LOG_DEFAULT, "Failed to start tracer: %d (attempt %d)", ret, attempt); 127 | sleep(1); 128 | } 129 | } 130 | 131 | if (ret != TRACER_SUCCESS) { 132 | tracer_cleanup(tracer); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/libobjsee/interception/arguments/arg_capture.h: -------------------------------------------------------------------------------- 1 | // 2 | // arg_capture.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/30/25. 6 | // 7 | 8 | #include "tracer_types.h" 9 | 10 | void capture_arguments(tracer_t *tracer_ctx, struct tracer_thread_context_frame_t *frame, void *stack_base, tracer_event_t *event); 11 | -------------------------------------------------------------------------------- /src/libobjsee/interception/arguments/arg_description.h: -------------------------------------------------------------------------------- 1 | // 2 | // arg_description.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 2/7/25. 6 | // 7 | 8 | #ifndef ARG_DESCRIPTION_H 9 | #define ARG_DESCRIPTION_H 10 | 11 | #include "tracer_types.h" 12 | 13 | /** 14 | * @brief Get a human-readable description of an argument 15 | * @param arg The argument to describe 16 | * @param fmt The format to use 17 | * @param out_buf The buffer to write the description to 18 | * @param buf_size The size of the buffer 19 | * @return KERN_SUCCESS on success, otherwise an error code 20 | */ 21 | kern_return_t description_for_argument(const tracer_argument_t *arg, tracer_argument_format_t fmt, char *out_buf, size_t buf_size); 22 | 23 | #endif /* ARG_DESCRIPTION_H */ 24 | -------------------------------------------------------------------------------- /src/libobjsee/interception/arguments/objc_arg_description.c: -------------------------------------------------------------------------------- 1 | // 2 | // objc_arg_description.c 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 2/7/25. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include "msgSend_hook.h" 12 | 13 | // Cache the result of -description calls to avoid repeated calls 14 | static char *g_description_cache[1024] = {0}; 15 | static size_t g_description_cache_count = 0; 16 | static os_unfair_lock g_description_cache_lock = OS_UNFAIR_LOCK_INIT; 17 | 18 | // Cache the description IMP for classes to avoid repeated lookups 19 | static void *g_imp_cache[1024] = {0}; 20 | static size_t g_imp_cache_count = 0; 21 | static os_unfair_lock g_imp_cache_lock = OS_UNFAIR_LOCK_INIT; 22 | 23 | 24 | static SEL description_selector(void) { 25 | static SEL descriptionSel = NULL; 26 | if (descriptionSel == NULL) { 27 | descriptionSel = sel_registerName("description"); 28 | } 29 | return descriptionSel; 30 | } 31 | 32 | static IMP get_description_imp_for_class(Class cls) { 33 | if (cls == NULL) { 34 | return NULL; 35 | } 36 | 37 | os_unfair_lock_lock(&g_imp_cache_lock); 38 | 39 | for (size_t i = 0; i < g_imp_cache_count; i += 2) { 40 | if (g_imp_cache[i] == cls) { 41 | IMP existingImp = (IMP)g_imp_cache[i + 1]; 42 | os_unfair_lock_unlock(&g_imp_cache_lock); 43 | return existingImp; 44 | } 45 | } 46 | 47 | SEL descriptionSel = description_selector(); 48 | IMP descriptionImp = NULL; 49 | if (class_respondsToSelector(cls, descriptionSel)) { 50 | descriptionImp = class_getMethodImplementation(cls, descriptionSel); 51 | } 52 | 53 | if (descriptionImp != NULL && g_imp_cache_count < 1022) { 54 | g_imp_cache[g_imp_cache_count] = cls; 55 | g_imp_cache[g_imp_cache_count + 1] = descriptionImp; 56 | g_imp_cache_count += 2; 57 | } 58 | 59 | os_unfair_lock_unlock(&g_imp_cache_lock); 60 | return descriptionImp; 61 | } 62 | 63 | static const char *build_objc_description_for_object(void *address, Class obj_class) { 64 | if (address == NULL || obj_class == NULL) { 65 | return NULL; 66 | } 67 | 68 | IMP descriptionImp = get_description_imp_for_class(obj_class); 69 | if (descriptionImp == NULL) { 70 | return NULL; 71 | } 72 | 73 | id object = (id)address; 74 | SEL descriptionSel = description_selector(); 75 | id descriptionString = ((id (*)(id, SEL))descriptionImp)(object, descriptionSel); 76 | if (descriptionString == NULL) { 77 | return NULL; 78 | } 79 | 80 | void *orig_objc_msgSend = get_original_objc_msgSend(); 81 | if (orig_objc_msgSend == NULL) { 82 | return NULL; 83 | } 84 | 85 | const char *utf8String = ((const char *(*)(id, SEL))orig_objc_msgSend)(descriptionString, sel_registerName("UTF8String")); 86 | if (utf8String == NULL) { 87 | return NULL; 88 | } 89 | 90 | // For string types, use objc style quoting (@"string") 91 | if (objc_opt_isKindOfClass(object, objc_getClass("NSString"))) { 92 | char *quoted_string = malloc(strlen(utf8String) + 3); 93 | if (quoted_string == NULL) { 94 | return NULL; 95 | } 96 | 97 | quoted_string[0] = '@'; 98 | quoted_string[1] = '"'; 99 | strcpy(quoted_string + 2, utf8String); 100 | char *newline = strchr(quoted_string, '\n'); 101 | if (newline != NULL) { 102 | newline[0] = '\0'; 103 | } 104 | 105 | size_t final_len = strlen(quoted_string); 106 | quoted_string[final_len] = '"'; 107 | quoted_string[final_len + 1] = '\0'; 108 | return quoted_string; 109 | } 110 | 111 | return strdup(utf8String); 112 | } 113 | 114 | const char *lookup_description_for_address(void *address, Class obj_class) { 115 | if (address == NULL || obj_class == NULL) { 116 | return NULL; 117 | } 118 | 119 | const char *result_desc = NULL; 120 | 121 | os_unfair_lock_lock(&g_description_cache_lock); 122 | for (size_t i = 0; i < g_description_cache_count; i += 2) { 123 | if (g_description_cache[i] == address) { 124 | result_desc = (const char *)g_description_cache[i + 1]; 125 | os_unfair_lock_unlock(&g_description_cache_lock); 126 | return result_desc; 127 | } 128 | } 129 | os_unfair_lock_unlock(&g_description_cache_lock); 130 | 131 | const char *built_desc = build_objc_description_for_object(address, obj_class); 132 | if (built_desc == NULL) { 133 | return NULL; 134 | } 135 | 136 | os_unfair_lock_lock(&g_description_cache_lock); 137 | 138 | for (size_t i = 0; i < g_description_cache_count; i += 2) { 139 | if (g_description_cache[i] == address) { 140 | result_desc = (const char *)g_description_cache[i + 1]; 141 | free((void*)built_desc); 142 | os_unfair_lock_unlock(&g_description_cache_lock); 143 | return result_desc; 144 | } 145 | } 146 | 147 | if (g_description_cache_count < 1022) { 148 | size_t len = strnlen(built_desc, 1023); 149 | char *desc_buffer_copy = (char *)malloc(len + 1); 150 | 151 | if (desc_buffer_copy) { 152 | strncpy(desc_buffer_copy, built_desc, len); 153 | desc_buffer_copy[len] = '\0'; 154 | 155 | g_description_cache[g_description_cache_count] = address; 156 | g_description_cache[g_description_cache_count + 1] = desc_buffer_copy; 157 | g_description_cache_count += 2; 158 | 159 | result_desc = desc_buffer_copy; 160 | free((void *)built_desc); 161 | } 162 | else { 163 | result_desc = built_desc; 164 | } 165 | } 166 | else { 167 | result_desc = built_desc; 168 | } 169 | 170 | os_unfair_lock_unlock(&g_description_cache_lock); 171 | return result_desc; 172 | } 173 | -------------------------------------------------------------------------------- /src/libobjsee/interception/arguments/objc_arg_description.h: -------------------------------------------------------------------------------- 1 | // 2 | // objc_arg_description.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 2/7/25. 6 | // 7 | 8 | #ifndef OBJC_ARG_DESCRIPTION_H 9 | #define OBJC_ARG_DESCRIPTION_H 10 | 11 | 12 | /** 13 | * @brief Lookup the description of an objective-c object at a given address 14 | * @param address The address of the object 15 | * @param obj_class The objective-c class of the object at address 16 | * @return The description of the object, or NULL if it could not be determined 17 | * 18 | * @note The returned string is owned by a cache and should not be freed 19 | */ 20 | const char *lookup_description_for_address(void *address, Class obj_class); 21 | 22 | 23 | #endif /* OBJC_ARG_DESCRIPTION_H */ 24 | -------------------------------------------------------------------------------- /src/libobjsee/interception/arguments/realized_class_tracking.c: -------------------------------------------------------------------------------- 1 | // 2 | // realized_class_tracking.c 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/30/25. 6 | // 7 | 8 | #include 9 | #include "tracer_internal.h" 10 | #include 11 | 12 | struct class_tracking_state { 13 | _Atomic bool initialized; 14 | os_unfair_lock lock; 15 | _Atomic(Class) *seen_classes; 16 | size_t seen_classes_count; 17 | size_t capacity; 18 | }; 19 | 20 | static struct class_tracking_state g_class_tracking = { 21 | .initialized = false, 22 | .lock = OS_UNFAIR_LOCK_INIT, 23 | .seen_classes = NULL, 24 | .seen_classes_count = 0, 25 | .capacity = 1024 26 | }; 27 | 28 | static kern_return_t init_class_tracking(void) { 29 | if (atomic_load(&g_class_tracking.initialized) == true) { 30 | return KERN_SUCCESS; 31 | } 32 | 33 | os_unfair_lock_lock(&g_class_tracking.lock); 34 | 35 | if (atomic_load(&g_class_tracking.initialized) == true) { 36 | os_unfair_lock_unlock(&g_class_tracking.lock); 37 | return KERN_SUCCESS; 38 | } 39 | 40 | size_t initial_size = 0; 41 | if (__builtin_mul_overflow(g_class_tracking.capacity, sizeof(_Atomic(Class)), &initial_size)) { 42 | os_unfair_lock_unlock(&g_class_tracking.lock); 43 | return KERN_FAILURE; 44 | } 45 | 46 | g_class_tracking.seen_classes = (_Atomic(Class) *)calloc(g_class_tracking.capacity, sizeof(_Atomic(Class))); 47 | if (g_class_tracking.seen_classes == NULL) { 48 | os_unfair_lock_unlock(&g_class_tracking.lock); 49 | return KERN_FAILURE; 50 | } 51 | 52 | atomic_thread_fence(memory_order_release); 53 | atomic_store(&g_class_tracking.initialized, true); 54 | os_unfair_lock_unlock(&g_class_tracking.lock); 55 | return KERN_SUCCESS; 56 | } 57 | 58 | kern_return_t has_seen_class(Class cls) { 59 | if (cls == NULL) { 60 | return KERN_FAILURE; 61 | } 62 | 63 | if (atomic_load(&g_class_tracking.initialized) == false) { 64 | kern_return_t init_result = init_class_tracking(); 65 | if (init_result != KERN_SUCCESS) { 66 | return KERN_FAILURE; 67 | } 68 | } 69 | 70 | os_unfair_lock_lock(&g_class_tracking.lock); 71 | _Atomic(Class) *classes = g_class_tracking.seen_classes; 72 | size_t count = g_class_tracking.seen_classes_count; 73 | bool found = false; 74 | 75 | if (classes != NULL) { 76 | for (size_t i = 0; i < count && i < g_class_tracking.capacity; i++) { 77 | Class stored_class = atomic_load(&classes[i]); 78 | if (stored_class == cls) { 79 | found = true; 80 | break; 81 | } 82 | } 83 | } 84 | 85 | os_unfair_lock_unlock(&g_class_tracking.lock); 86 | return found ? KERN_SUCCESS : KERN_FAILURE; 87 | } 88 | 89 | kern_return_t record_class_encounter(Class cls) { 90 | if (cls == NULL) { 91 | return KERN_FAILURE; 92 | } 93 | 94 | if (atomic_load(&g_class_tracking.initialized) == false) { 95 | if (init_class_tracking() != KERN_SUCCESS) { 96 | return KERN_FAILURE; 97 | } 98 | } 99 | 100 | os_unfair_lock_lock(&g_class_tracking.lock); 101 | 102 | if (g_class_tracking.seen_classes == NULL) { 103 | os_unfair_lock_unlock(&g_class_tracking.lock); 104 | return KERN_FAILURE; 105 | } 106 | 107 | size_t current_count = g_class_tracking.seen_classes_count; 108 | if (current_count == SIZE_MAX) { 109 | os_unfair_lock_unlock(&g_class_tracking.lock); 110 | return KERN_FAILURE; 111 | } 112 | 113 | if (current_count >= g_class_tracking.capacity) { 114 | size_t new_capacity = g_class_tracking.capacity; 115 | if (__builtin_mul_overflow(new_capacity, 2, &new_capacity)) { 116 | os_unfair_lock_unlock(&g_class_tracking.lock); 117 | return KERN_FAILURE; 118 | } 119 | 120 | size_t new_size = 0; 121 | if (__builtin_mul_overflow(new_capacity, sizeof(_Atomic(Class)), &new_size)) { 122 | os_unfair_lock_unlock(&g_class_tracking.lock); 123 | return KERN_FAILURE; 124 | } 125 | 126 | _Atomic(Class) *new_array = (_Atomic(Class) *)realloc(g_class_tracking.seen_classes, new_size); 127 | if (new_array == NULL) { 128 | os_unfair_lock_unlock(&g_class_tracking.lock); 129 | return KERN_FAILURE; 130 | } 131 | memset(new_array + g_class_tracking.capacity, 0, new_size - (g_class_tracking.capacity * sizeof(_Atomic(Class)))); 132 | 133 | g_class_tracking.seen_classes = new_array; 134 | g_class_tracking.capacity = new_capacity; 135 | } 136 | 137 | _Atomic(Class) *target = &g_class_tracking.seen_classes[current_count]; 138 | 139 | atomic_store(target, cls); 140 | g_class_tracking.seen_classes_count++; 141 | 142 | os_unfair_lock_unlock(&g_class_tracking.lock); 143 | return KERN_SUCCESS; 144 | } 145 | -------------------------------------------------------------------------------- /src/libobjsee/interception/arguments/realized_class_tracking.h: -------------------------------------------------------------------------------- 1 | // 2 | // realized_class_tracking.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/30/25. 6 | // 7 | 8 | #ifndef realized_class_tracking_h 9 | #define realized_class_tracking_h 10 | 11 | #include 12 | 13 | // Capturing arguments within a objc_msgSend() hook creates the potential for interactions with unrealized classes. Attempting to read metadata about such classes 14 | // will kill the process. To work around this, details are not captured for objects when it's the first occurrence of that class. Subsequent occurrences will be captured 15 | 16 | /** 17 | * @brief Returns whether or not the class has been seen before (passed through record_class_encounter()) 18 | * @param cls The class to check 19 | * @return KERN_SUCCESS if the class has been seen, otherwise an error code 20 | */ 21 | kern_return_t has_seen_class(Class cls); 22 | 23 | /** 24 | * @brief Records that a class has been seen 25 | * @param cls The class to record 26 | * @return KERN_SUCCESS on success, otherwise an error code 27 | */ 28 | kern_return_t record_class_encounter(Class cls); 29 | 30 | #endif /* realized_class_tracking_h */ 31 | -------------------------------------------------------------------------------- /src/libobjsee/interception/msgSend_hook.h: -------------------------------------------------------------------------------- 1 | // 2 | // msgSend_hook.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 11/30/24. 6 | // 7 | 8 | #include "tracer_internal.h" 9 | 10 | extern void (*original_objc_msgSend)(void); 11 | 12 | void *get_original_objc_msgSend(void); 13 | 14 | tracer_result_t init_message_interception(tracer_t *tracer); 15 | -------------------------------------------------------------------------------- /src/libobjsee/interception/rebind.h: -------------------------------------------------------------------------------- 1 | // 2 | // rebind.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 11/30/24. 6 | // 7 | 8 | struct symbol_rebinding_t { 9 | const char * _Nonnull name; 10 | void * _Nonnull replacement; 11 | uint32_t num_symbols_rebound; 12 | }; 13 | 14 | struct symbol_rebinding_t * _Nullable hook_function(const char * _Nonnull symbol_to_hook, void * _Nonnull replacement_func); 15 | -------------------------------------------------------------------------------- /src/libobjsee/interception/selector_deny_list.c: -------------------------------------------------------------------------------- 1 | // 2 | // runtime_utils.m 3 | // 4 | // Created by Ethan Arbuckle on 11/30/24. 5 | // 6 | 7 | #include 8 | #include "tracer_internal.h" 9 | 10 | 11 | static const uint32_t selector_skip_list[] = { 12 | 0x033DB2A4, // isKindOfClass: 13 | 0x0390DC47, // zone 14 | 0x1036AE7E, // release 15 | 0x378D6F42, // allocWithZone: 16 | 0x5B52EC16, // _tryRetain 17 | 0x767A90E3, // retainCount 18 | 0x88BCC57C, // retain 19 | 0xAB3E0BFF, // class 20 | 0xB271BD4D, // _xref_dispose 21 | 0xB8F35F41, // .cxx_destruct 22 | 0xBAB1BB16, // alloc 23 | 0xC8C9FA1F, // autorelease 24 | 0xD9929EB3, // dealloc 25 | 0xEFF52FB5, // _isDeallocating 26 | }; 27 | static const size_t selector_skip_list_len = 14; 28 | 29 | __attribute__((aligned(16), hot, always_inline)) 30 | static inline bool hash_in_denylist(uint32_t hash) { 31 | if (selector_skip_list_len == 0) { 32 | return false; 33 | } 34 | size_t left = 0; 35 | size_t right = selector_skip_list_len - 1; 36 | 37 | while (left <= right) { 38 | size_t mid = left + ((right - left) >> 1); 39 | uint32_t mid_hash = selector_skip_list[mid]; 40 | if (mid_hash == hash) { 41 | return true; 42 | } 43 | 44 | if (mid_hash < hash) { 45 | left = mid + 1; 46 | } 47 | else { 48 | if (mid == 0) { 49 | return false; 50 | } 51 | right = mid - 1; 52 | } 53 | } 54 | 55 | return false; 56 | } 57 | 58 | __attribute__((aligned(16), hot, always_inline)) 59 | bool selector_is_denylisted(SEL selector) { 60 | if (selector == NULL) { 61 | return false; 62 | } 63 | 64 | const char *selector_name = sel_getName(selector); 65 | if (selector_name == NULL || selector_name[0] == '\0') { 66 | return false; 67 | } 68 | 69 | char first_char = selector_name[0]; 70 | if (first_char == 's') { 71 | return false; 72 | } 73 | else if (first_char == '.') { 74 | return true; 75 | } 76 | 77 | uint32_t hash = fnv1a_hash(selector_name); 78 | return hash_in_denylist(hash); 79 | } 80 | -------------------------------------------------------------------------------- /src/libobjsee/interception/selector_deny_list.h: -------------------------------------------------------------------------------- 1 | // 2 | // selector_deny_list.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 11/30/24. 6 | // 7 | 8 | 9 | #ifndef SELECTOR_DENY_LIST_H 10 | #define SELECTOR_DENY_LIST_H 11 | 12 | 13 | bool selector_is_denylisted(SEL selector); 14 | 15 | #endif /* SELECTOR_DENY_LIST_H */ 16 | 17 | -------------------------------------------------------------------------------- /src/libobjsee/tracing/objc-internal.h: -------------------------------------------------------------------------------- 1 | // 2 | // objc-internal.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 2/13/25. 6 | // 7 | 8 | #ifndef objc_internal_h 9 | #define objc_internal_h 10 | 11 | #include 12 | 13 | #define _OBJC_TAG_MASK (1UL<<63) 14 | #define _OBJC_TAG_INDEX_SHIFT 0 15 | #define _OBJC_TAG_SLOT_SHIFT 0 16 | #define _OBJC_TAG_PAYLOAD_LSHIFT 1 17 | #define _OBJC_TAG_PAYLOAD_RSHIFT 4 18 | #define _OBJC_TAG_EXT_MASK (_OBJC_TAG_MASK | 0x7UL) 19 | #define _OBJC_TAG_NO_OBFUSCATION_MASK ((1UL<<62) | _OBJC_TAG_EXT_MASK) 20 | #define _OBJC_TAG_CONSTANT_POINTER_MASK ~(_OBJC_TAG_EXT_MASK | ((uintptr_t)_OBJC_TAG_EXT_SLOT_MASK << _OBJC_TAG_EXT_SLOT_SHIFT)) 21 | #define _OBJC_TAG_EXT_INDEX_SHIFT 55 22 | #define _OBJC_TAG_EXT_SLOT_SHIFT 55 23 | #define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 9 24 | #define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12 25 | 26 | static inline bool _objc_isTaggedPointer(const void * _Nullable ptr) { 27 | return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK; 28 | } 29 | 30 | 31 | #endif /* objc_internal_h */ 32 | -------------------------------------------------------------------------------- /src/libobjsee/tracing/signal_guard.h: -------------------------------------------------------------------------------- 1 | // 2 | // signal_guard.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 2/5/25. 6 | // 7 | 8 | #ifndef signal_guard_h 9 | #define signal_guard_h 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | /** 17 | * Block signals while executing a block of code. 18 | * @param code The block of code to execute. 19 | * @return The result of the block of code. 20 | * @note Blocked signals are queued and will eventually be delivered 21 | */ 22 | #define WHILE_BLOCKING_SIGNALS(code) ({ \ 23 | __typeof__(code) __result = 0; \ 24 | sigset_t block_mask, old_mask; \ 25 | if (sigfillset(&block_mask) == 0 && sigprocmask(SIG_BLOCK, &block_mask, &old_mask) == 0) { \ 26 | __result = code; \ 27 | sigprocmask(SIG_SETMASK, &old_mask, NULL); \ 28 | } \ 29 | __result; \ 30 | }) 31 | 32 | /** 33 | * Execute a block of code while ignoring signals. 34 | * @param code The block of code to execute. 35 | * @return The result of the block of code. 36 | * @note The signals will never hit the original signal handler. 37 | */ 38 | #define WHILE_IGNORING_SIGNALS(code) do { \ 39 | if (!g_sig_ignoring && g_sig_ignore_depth < 2) { \ 40 | signal_handlers_t __old_handlers; \ 41 | g_sig_ignore_depth++; \ 42 | g_sig_ignoring = 1; \ 43 | \ 44 | if (install_signal_handlers(&__old_handlers) == 0) { \ 45 | if (sigsetjmp(g_sig_ignore_jmpbuf, 1) == 0) { \ 46 | code; \ 47 | } \ 48 | else { } \ 49 | restore_signal_handlers(&__old_handlers); \ 50 | } \ 51 | g_sig_ignoring = 0; \ 52 | g_sig_ignore_depth--; \ 53 | } \ 54 | } while(0) 55 | 56 | 57 | static __thread sigjmp_buf g_sig_ignore_jmpbuf; 58 | static __thread volatile sig_atomic_t g_sig_ignoring = 0; 59 | static __thread int g_sig_ignore_depth = 0; 60 | 61 | typedef struct { 62 | struct sigaction sa_segv; 63 | struct sigaction sa_bus; 64 | struct sigaction sa_kill; 65 | struct sigaction sa_ill; 66 | struct sigaction sa_fpe; 67 | } signal_handlers_t; 68 | 69 | static void _sig_ignoring_handler(int signo) { 70 | if (g_sig_ignoring) { 71 | os_log(OS_LOG_DEFAULT, "Handler called for signal %d at depth %d\n", signo, g_sig_ignore_depth); 72 | siglongjmp(g_sig_ignore_jmpbuf, signo); 73 | } 74 | } 75 | 76 | static inline bool install_signal_handlers(signal_handlers_t *old_handlers) { 77 | // Block signals while installing the new handlers 78 | return WHILE_BLOCKING_SIGNALS(({ 79 | struct sigaction sa; 80 | memset(&sa, 0, sizeof(sa)); 81 | sa.sa_handler = _sig_ignoring_handler; 82 | sa.sa_flags = 0; 83 | sigemptyset(&sa.sa_mask); 84 | 85 | sigaction(SIGSEGV, &sa, &old_handlers->sa_segv) == 0 && 86 | sigaction(SIGBUS, &sa, &old_handlers->sa_bus) == 0 && 87 | sigaction(SIGKILL, &sa, &old_handlers->sa_kill) == 0 && 88 | sigaction(SIGILL, &sa, &old_handlers->sa_ill) == 0 && 89 | sigaction(SIGFPE, &sa, &old_handlers->sa_fpe) == 0; 90 | })); 91 | } 92 | 93 | static inline void restore_signal_handlers(const signal_handlers_t *old_handlers) { 94 | WHILE_BLOCKING_SIGNALS(({ 95 | sigaction(SIGSEGV, &old_handlers->sa_segv, NULL); 96 | sigaction(SIGBUS, &old_handlers->sa_bus, NULL); 97 | sigaction(SIGKILL, &old_handlers->sa_kill, NULL); 98 | sigaction(SIGILL, &old_handlers->sa_ill, NULL); 99 | sigaction(SIGFPE, &old_handlers->sa_fpe, NULL); 100 | })); 101 | } 102 | 103 | #endif /* signal_guard_h */ 104 | -------------------------------------------------------------------------------- /src/libobjsee/tracing/tracer.h: -------------------------------------------------------------------------------- 1 | // 2 | // tracer.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 11/30/24. 6 | // 7 | 8 | #ifndef TRACER_H 9 | #define TRACER_H 10 | 11 | #include "tracer_types.h" 12 | 13 | #ifndef OBJSEE_LIB_VERSION 14 | #define OBJSEE_LIB_VERSION "0.0.1" 15 | #endif 16 | 17 | struct tracer_error_s { 18 | char message[256]; 19 | }; 20 | 21 | typedef struct tracer_context_t tracer_t; 22 | typedef struct tracer_error_s tracer_error_t; 23 | 24 | tracer_t *tracer_create(void); 25 | tracer_t *tracer_create_with_error(tracer_error_t **error); 26 | tracer_t *tracer_create_with_config(tracer_config_t config, tracer_error_t **error); 27 | 28 | void tracer_set_output(tracer_t *tracer, tracer_transport_type_t output); 29 | void tracer_set_output_stdout(tracer_t *tracer); 30 | void tracer_set_output_file(tracer_t *tracer, const char *path); 31 | void tracer_set_output_socket(tracer_t *tracer, const char *host, uint16_t port); 32 | void tracer_set_output_handler(tracer_t *tracer, tracer_event_handler_t *handler, void *context); 33 | 34 | void tracer_set_format_options(tracer_t *tracer, tracer_format_options_t format); 35 | void tracer_set_arg_detail(tracer_t *tracer, tracer_argument_format_t arg_format); 36 | 37 | void tracer_format_enable_color(tracer_t *tracer, bool enable); 38 | void tracer_format_enable_indent(tracer_t *tracer, bool enable); 39 | void tracer_format_enable_thread_id(tracer_t *tracer, bool enable); 40 | 41 | void tracer_include_pattern(tracer_t *tracer, const char *class_pattern, const char *method_pattern); 42 | void tracer_exclude_pattern(tracer_t *tracer, const char *class_pattern, const char *method_pattern); 43 | void tracer_include_class(tracer_t *tracer, const char *class_pattern); 44 | void tracer_exclude_class(tracer_t *tracer, const char *class_pattern); 45 | void tracer_include_method(tracer_t *tracer, const char *method_pattern); 46 | void tracer_exclude_method(tracer_t *tracer, const char *method_pattern); 47 | void tracer_include_image(tracer_t *tracer, const char *image_pattern); 48 | 49 | tracer_result_t tracer_add_filter(tracer_t *tracer, const tracer_filter_t *filter); 50 | tracer_result_t tracer_start(tracer_t *tracer); 51 | tracer_result_t tracer_stop(tracer_t *tracer); 52 | tracer_result_t tracer_cleanup(tracer_t *tracer); 53 | 54 | const char *tracer_get_last_error(tracer_t *tracer); 55 | void free_error(tracer_error_t *error); 56 | 57 | #endif // TRACER_H 58 | -------------------------------------------------------------------------------- /src/libobjsee/tracing/tracer_internal.h: -------------------------------------------------------------------------------- 1 | // 2 | // tracer_internal.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 11/30/24. 6 | // 7 | #ifndef TRACER_INTERNAL_H 8 | #define TRACER_INTERNAL_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include "tracer_types.h" 14 | #include "tracer.h" 15 | 16 | #define TRACER_MAX_STACK_DEPTH 256 17 | #define TRACER_BUFFER_SIZE 2048 18 | #define INITIAL_STACK_FRAMES 256 19 | 20 | extern BOOL objc_opt_isKindOfClass(id _Nullable obj, Class _Nullable cls); 21 | extern size_t malloc_size(const void * _Nonnull); 22 | extern const char * _Nullable _Block_signature(void * _Nonnull aBlock); 23 | extern kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t * _Nonnull outsize); 24 | 25 | struct BlockDescriptor { 26 | unsigned long reserved; 27 | unsigned long size; 28 | void (* _Nullable copy)(void * _Nonnull dst, void * _Nonnull src); 29 | void (* _Nonnull dispose)(void *_Nonnull); 30 | const char * _Nullable signature; 31 | }; 32 | 33 | struct BlockLiteral { 34 | void * _Nonnull isa; 35 | int flags; 36 | int reserved; 37 | void (* _Nonnull invoke)(void); 38 | struct BlockDescriptor * _Nonnull descriptor; 39 | }; 40 | 41 | bool is_valid_pointer(void * _Nonnull ptr); 42 | 43 | typedef struct tracer_thread_context_frame_t { 44 | SEL _Nonnull _cmd; 45 | const char * _Nonnull selector_name; 46 | bool selector_is_class_method; 47 | const char * _Nullable image_path; 48 | Class _Nonnull self_class; 49 | const char * _Nonnull self_class_name; 50 | uintptr_t lr; 51 | bool traced; 52 | } __attribute__((packed)) tracer_thread_context_frame_t; 53 | 54 | typedef struct tracer_thread_context_t { 55 | uint16_t thread_id; 56 | uint32_t stack_depth; 57 | uint32_t trace_depth; 58 | struct tracer_thread_context_frame_t frames[INITIAL_STACK_FRAMES]; 59 | uint32_t frame_capacity; 60 | 61 | struct { 62 | Class _Nullable cls; 63 | const char * _Nullable name; 64 | bool is_meta; 65 | } last_class_cache; 66 | 67 | struct { 68 | SEL _Nullable sel; 69 | const char * _Nullable name; 70 | } last_sel_cache; 71 | 72 | bool capture_arguments; 73 | } __attribute__((aligned(64))) tracer_thread_context_t; 74 | 75 | typedef struct tracer_context_t { 76 | bool initialized; 77 | bool running; 78 | tracer_config_t config; 79 | pthread_rwlock_t filter_lock; 80 | void * _Nullable transport_context; 81 | pthread_mutex_t transport_lock; 82 | pthread_key_t thread_key; 83 | char last_error[256]; 84 | pthread_mutex_t error_lock; 85 | } tracer_context_t; 86 | 87 | tracer_result_t tracer_context_init(tracer_t * _Nonnull tracer); 88 | tracer_thread_context_t * _Nullable tracer_get_thread_context(tracer_t * _Nonnull tracer); 89 | 90 | 91 | bool tracer_should_trace(tracer_t * _Nonnull tracer, tracer_thread_context_frame_t * _Nonnull frame); 92 | void tracer_set_error(tracer_t * _Nonnull tracer, const char * _Nonnull format, ...); 93 | 94 | __attribute__((always_inline, hot)) 95 | static inline uint32_t fnv1a_hash(const char * _Nonnull str) { 96 | uint32_t hash = 2166136261u; 97 | while (*str) { 98 | hash ^= (uint8_t)*str++; 99 | hash *= 16777619u; 100 | } 101 | return hash; 102 | } 103 | 104 | #endif // TRACER_INTERNAL_H 105 | -------------------------------------------------------------------------------- /src/libobjsee/transport/event_handler.h: -------------------------------------------------------------------------------- 1 | // 2 | // event_handler.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 11/30/24. 6 | // 7 | 8 | #include "tracer_internal.h" 9 | 10 | void tracer_handle_event(tracer_t *tracer, tracer_event_t *event); 11 | 12 | void cleanup_event_handler(void); 13 | tracer_result_t init_event_handler(tracer_t *tracer); 14 | 15 | -------------------------------------------------------------------------------- /src/libobjsee/transport/transport.h: -------------------------------------------------------------------------------- 1 | // 2 | // transport.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 11/30/24. 6 | // 7 | 8 | #include "tracer_internal.h" 9 | #include 10 | 11 | typedef struct { 12 | char *data; 13 | size_t length; 14 | } queued_message_t; 15 | 16 | 17 | typedef struct { 18 | union { 19 | int fd; 20 | void *custom_handle; 21 | }; 22 | 23 | struct { 24 | queued_message_t *messages; 25 | size_t capacity; 26 | size_t count; 27 | pthread_mutex_t lock; 28 | pthread_cond_t not_full; 29 | pthread_cond_t not_empty; 30 | } queue; 31 | 32 | bool running; 33 | pthread_t transport_thread; 34 | 35 | tracer_transport_type_t type; 36 | pthread_mutex_t write_lock; 37 | } transport_context_t; 38 | 39 | tracer_result_t transport_init(tracer_t *tracer, const tracer_transport_config_t *config); 40 | tracer_result_t transport_send(tracer_t *tracer, const void *data, size_t length); 41 | -------------------------------------------------------------------------------- /src/libobjsee/type_decoding/blocks.h: -------------------------------------------------------------------------------- 1 | // 2 | // blocks.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/10/24. 6 | // 7 | 8 | #ifndef BLOCKS_H 9 | #define BLOCKS_H 10 | 11 | #include 12 | #include 13 | 14 | /** 15 | * @brief Describe a block's type signature in a human-readable format 16 | * 17 | * @param block The block to describe 18 | * @return The description of the block 19 | * @note The returned string is malloc'd and must be freed by the caller 20 | */ 21 | kern_return_t get_block_description(id block, char **out_description); 22 | 23 | 24 | #endif /* BLOCKS_H */ 25 | -------------------------------------------------------------------------------- /src/libobjsee/type_decoding/encoding_description.h: -------------------------------------------------------------------------------- 1 | // 2 | // encoding_description.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 1/4/25. 6 | // 7 | 8 | #ifndef encoding_description_h 9 | #define encoding_description_h 10 | 11 | #include 12 | 13 | 14 | /** 15 | * @brief Parse a struct encoding and return a human-readable description 16 | * 17 | * @param encoding The encoding to parse 18 | * @return The description of the struct 19 | * @note The returned string is malloc'd and must be freed by the caller 20 | */ 21 | char *get_struct_description_from_type_encoding(const char *encoding); 22 | 23 | 24 | /** 25 | * @brief Get the name of a type from its type encoding 26 | * 27 | * @param type_encoding The type encoding 28 | * @return The name of the type 29 | */ 30 | const char *get_name_of_type_from_type_encoding(const char *type_encoding); 31 | 32 | 33 | #endif /* encoding_description_h */ 34 | -------------------------------------------------------------------------------- /src/libobjsee/type_decoding/encoding_size.h: -------------------------------------------------------------------------------- 1 | // 2 | // encoding_size.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 1/11/25. 6 | // 7 | 8 | #ifndef encoding_size_h 9 | #define encoding_size_h 10 | 11 | #include 12 | 13 | 14 | /** 15 | * @brief Get the size of a type from its type encoding 16 | * 17 | * @param type_encoding The type encoding 18 | * @return The size of the type 19 | */ 20 | size_t get_size_of_type_from_type_encoding(const char *type_encoding); 21 | 22 | 23 | /** 24 | * @brief Get the offsets of arguments in a method signature 25 | * 26 | * @param type_encoding The method signature 27 | * @param offsets The array to store the offsets in 28 | * @param arg_count The number of arguments 29 | * 30 | * @return KERN_SUCCESS on success, or an error code on failure 31 | */ 32 | kern_return_t get_offsets_of_args_using_type_encoding(const char *type_encoding, size_t *offsets, size_t arg_count); 33 | 34 | #endif /* encoding_size_h */ 35 | -------------------------------------------------------------------------------- /src/libobjseeTests/BlockDescriptionTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // BlockDescriptionTests.m 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 2/9/25. 6 | // 7 | 8 | #import 9 | #import "blocks.h" 10 | 11 | @interface BlockDescriptionTests : XCTestCase 12 | @end 13 | 14 | @implementation BlockDescriptionTests 15 | 16 | - (void)_assertBlock:(id)block matches:(const char *)expected { 17 | char *decoded_block_signature = NULL; 18 | XCTAssertEqual(get_block_description(block, &decoded_block_signature), KERN_SUCCESS); 19 | XCTAssertEqualObjects(@(decoded_block_signature), @(expected)); 20 | free(decoded_block_signature); 21 | } 22 | 23 | - (void)testBasicBlock { 24 | void (^block)(void) = ^{}; 25 | [self _assertBlock:block matches:"(void (^)(void))"]; 26 | } 27 | 28 | - (void)testParameterBlock { 29 | int (^block)(int, float) = ^(int x, float y) { return x; }; 30 | [self _assertBlock:block matches:"(int (^)(int, float))"]; 31 | } 32 | 33 | - (void)testObjectBlock { 34 | void (^block)(id, NSString *) = ^(id obj, NSString *str) {}; 35 | [self _assertBlock:block matches:"(void (^)(id, NSString))"]; 36 | } 37 | 38 | - (void)testPointerBlock { 39 | void (^block)(int *, char **) = ^(int *x, char **y) {}; 40 | [self _assertBlock:block matches:"(void (^)(int *, char **))"]; 41 | } 42 | 43 | - (void)testNullBlock { 44 | XCTAssertEqual(get_block_description(NULL, NULL), KERN_INVALID_ARGUMENT); 45 | } 46 | 47 | - (void)testInvalidBlock { 48 | char *decoded_block_signature = NULL; 49 | XCTAssertEqual(get_block_description((__bridge id)((void *)0x1), &decoded_block_signature), KERN_INVALID_ARGUMENT); 50 | } 51 | 52 | - (void)testLongTypes { 53 | long long (^block)(long long, long long) = ^(long long x, long long y) { return y; }; 54 | [self _assertBlock:block matches:"(long long (^)(long long, long long))"]; 55 | } 56 | 57 | - (void)testBOOLType { 58 | BOOL (^block)(BOOL) = ^(BOOL x) { return x; }; 59 | [self _assertBlock:block matches:"(BOOL (^)(BOOL))"]; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /src/libobjseeTests/CoreSymbolicationTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreSymbolicationTests.m 3 | // libobjseeTests 4 | // 5 | // Created by Ethan Arbuckle on 2/9/25. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import "symbolication.h" 13 | 14 | @interface CoreSymbolicationTests : XCTestCase { 15 | pid_t _helperPid; 16 | task_t _helperTask; 17 | CSSymbolicatorRef _symbolicator; 18 | dispatch_source_t _exitSource; 19 | } 20 | @end 21 | 22 | @implementation CoreSymbolicationTests 23 | 24 | static void spawn_suspended_helper(pid_t *pid) { 25 | posix_spawnattr_t attr; 26 | posix_spawnattr_init(&attr); 27 | XCTAssertEqual(posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED), 0); 28 | 29 | extern char **environ; 30 | const char *self_path = NSBundle.mainBundle.executablePath.UTF8String; 31 | char *const argv[] = { (char *)self_path, NULL }; 32 | XCTAssertEqual( posix_spawn(pid, self_path, NULL, &attr, argv, environ), 0); 33 | posix_spawnattr_destroy(&attr); 34 | } 35 | 36 | - (void)setUp { 37 | spawn_suspended_helper(&_helperPid); 38 | XCTAssertEqual(task_for_pid(mach_task_self(), _helperPid, &_helperTask), KERN_SUCCESS); 39 | XCTAssertNotEqual(_helperTask, TASK_NULL); 40 | 41 | _symbolicator = create_symbolicator_with_task(_helperTask); 42 | XCTAssertFalse(cs_isnull(_symbolicator)); 43 | 44 | _exitSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, _helperPid, DISPATCH_PROC_EXIT, dispatch_get_main_queue()); 45 | dispatch_source_set_event_handler(_exitSource, ^{ 46 | kill(self->_helperPid, SIGKILL); 47 | self->_helperPid = -1; 48 | }); 49 | dispatch_resume(_exitSource); 50 | } 51 | 52 | - (void)tearDown { 53 | if (_helperPid > 0) { 54 | kill(_helperPid, SIGKILL); 55 | int status; 56 | waitpid(_helperPid, &status, 0); 57 | } 58 | 59 | if (_exitSource) { 60 | dispatch_source_cancel(_exitSource); 61 | _exitSource = NULL; 62 | } 63 | 64 | if (_helperTask != TASK_NULL) { 65 | mach_port_deallocate(mach_task_self(), _helperTask); 66 | _helperTask = TASK_NULL; 67 | } 68 | 69 | _symbolicator = (CSSymbolicatorRef){0}; 70 | } 71 | 72 | - (void)testSymbolicateDyldInHelper { 73 | CSSymbolOwnerRef dyld = get_symbol_owner_for_name(_symbolicator, "dyld"); 74 | XCTAssertFalse(cs_isnull(dyld)); 75 | 76 | CSSymbolRef dyldSymbol = get_symbol_from_owner_with_name(dyld, "dyld_all_image_infos"); 77 | XCTAssertFalse(cs_isnull(dyldSymbol)); 78 | 79 | CSRange symbolRange = get_range_for_symbol(dyldSymbol); 80 | XCTAssertGreaterThan(symbolRange.length, 0); 81 | 82 | const char *symbolName = get_name_for_symbol(dyldSymbol); 83 | XCTAssertNotEqual(symbolName, NULL); 84 | XCTAssertEqual(strcmp(symbolName, "dyld_all_image_infos"), 0); 85 | } 86 | 87 | - (void)testSymbolicateAllDyldSymbols { 88 | CSSymbolOwnerRef dyld = get_symbol_owner_for_name(_symbolicator, "dyld"); 89 | XCTAssertFalse(cs_isnull(dyld)); 90 | 91 | __block int symbolCount = 0; 92 | __block BOOL foundSymbol = NO; 93 | 94 | for_each_symbol(_symbolicator, ^(CSSymbolRef symbol) { 95 | symbolCount++; 96 | const char *name = get_name_for_symbol(symbol); 97 | if (name && strcmp(name, "dyld_all_image_infos") == 0) { 98 | foundSymbol = YES; 99 | } 100 | }); 101 | 102 | XCTAssertGreaterThan(symbolCount, 0); 103 | XCTAssertTrue(foundSymbol); 104 | } 105 | 106 | - (void)testSymbolicateAddress { 107 | CSSymbolOwnerRef dyld = get_symbol_owner_for_name(_symbolicator, "dyld"); 108 | XCTAssertFalse(cs_isnull(dyld)); 109 | 110 | CSSymbolRef dyldSymbol = get_symbol_from_owner_with_name(dyld, "task_register_dyld_shared_cache_image_info"); 111 | XCTAssertFalse(cs_isnull(dyldSymbol)); 112 | 113 | CSRange symbolRange = get_range_for_symbol(dyldSymbol); 114 | const char *symbolName = get_name_for_symbol_at_address(_symbolicator, symbolRange.location); 115 | XCTAssertNotEqual(symbolName, NULL); 116 | if (symbolName) { 117 | XCTAssertEqual(strcmp(symbolName, "task_register_dyld_shared_cache_image_info"), 0); 118 | } 119 | } 120 | 121 | - (void)testChildProcess { 122 | pid_t secondPid; 123 | spawn_suspended_helper(&secondPid); 124 | 125 | task_t secondTask; 126 | XCTAssertEqual(task_for_pid(mach_task_self(), secondPid, &secondTask), KERN_SUCCESS); 127 | 128 | CSSymbolicatorRef secondSymbolicator = create_symbolicator_with_task(secondTask); 129 | XCTAssertFalse(cs_isnull(secondSymbolicator)); 130 | 131 | CSSymbolOwnerRef dyld = get_symbol_owner_for_name(secondSymbolicator, "dyld"); 132 | XCTAssertFalse(cs_isnull(dyld)); 133 | 134 | kill(secondPid, SIGKILL); 135 | int status; 136 | waitpid(secondPid, &status, 0); 137 | mach_port_deallocate(mach_task_self(), secondTask); 138 | } 139 | 140 | - (void)testSymbolOwnerEnumeration { 141 | __block BOOL foundDyld = NO; 142 | for_each_symbol_owner(_symbolicator, ^(CSSymbolOwnerRef owner) { 143 | const char *path = get_image_path_for_symbol_owner(owner); 144 | if (path && strstr(path, "dyld") != NULL) { 145 | foundDyld = YES; 146 | } 147 | }); 148 | XCTAssertTrue(foundDyld); 149 | } 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /src/libobjseeTests/ObjcDescriptionTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjcDescriptionTests.m 3 | // libobjseeTests 4 | // 5 | // Created by Ethan Arbuckle on 2/9/25. 6 | // 7 | 8 | #import 9 | #import "tracer_internal.h" 10 | #import "objc_arg_description.h" 11 | 12 | @interface TestObject : NSObject 13 | @property (nonatomic, copy) NSString *customDescription; 14 | @end 15 | 16 | @implementation TestObject 17 | - (NSString *)description { 18 | return self.customDescription ?: [super description]; 19 | } 20 | @end 21 | 22 | @interface ObjcDescriptionTests : XCTestCase { 23 | TestObject *_testObject; 24 | } 25 | @end 26 | 27 | @implementation ObjcDescriptionTests 28 | 29 | - (void)setUp { 30 | [super setUp]; 31 | _testObject = [[TestObject alloc] init]; 32 | } 33 | 34 | - (void)tearDown { 35 | _testObject = nil; 36 | [super tearDown]; 37 | } 38 | 39 | - (void)testNullHandling { 40 | const char *result = lookup_description_for_address(NULL, NULL); 41 | XCTAssertEqual(result, NULL); 42 | 43 | result = lookup_description_for_address((__bridge void *)_testObject, NULL); 44 | XCTAssertEqual(result, NULL); 45 | 46 | result = lookup_description_for_address(NULL, [TestObject class]); 47 | XCTAssertEqual(result, NULL); 48 | } 49 | 50 | - (void)testBasicDescriptionLookup { 51 | _testObject.customDescription = @"TestDescription"; 52 | NSString *objcDesc = [_testObject description]; 53 | XCTAssertEqualObjects(objcDesc, @"TestDescription"); 54 | 55 | const char *utf8Str = [objcDesc UTF8String]; 56 | XCTAssertNotEqual(utf8Str, NULL); 57 | 58 | const char *result = lookup_description_for_address((__bridge void *)_testObject, [TestObject class]); 59 | XCTAssertNotEqual(result, NULL); 60 | if (result) { 61 | XCTAssertEqual(strcmp(result, "TestDescription"), 0); 62 | } 63 | } 64 | 65 | - (void)testDescriptionCaching { 66 | _testObject.customDescription = @"CacheTest"; 67 | 68 | const char *first = lookup_description_for_address((__bridge void *)_testObject, [TestObject class]); 69 | XCTAssertNotEqual(first, NULL); 70 | 71 | if (first) { 72 | XCTAssertEqual(strcmp(first, "CacheTest"), 0); 73 | 74 | const char *second = lookup_description_for_address((__bridge void *)_testObject, [TestObject class]); 75 | XCTAssertEqual(first, second); 76 | } 77 | } 78 | 79 | - (void)testMultipleObjects { 80 | TestObject *obj1 = [[TestObject alloc] init]; 81 | TestObject *obj2 = [[TestObject alloc] init]; 82 | 83 | obj1.customDescription = @"Description1"; 84 | obj2.customDescription = @"Description2"; 85 | 86 | const char *result1 = lookup_description_for_address((__bridge void *)obj1, [TestObject class]); 87 | const char *result2 = lookup_description_for_address((__bridge void *)obj2, [TestObject class]); 88 | 89 | XCTAssertNotEqual(result1, NULL); 90 | XCTAssertNotEqual(result2, NULL); 91 | XCTAssertNotEqual(result1, result2); 92 | XCTAssertEqual(strcmp(result1, "Description1"), 0); 93 | XCTAssertEqual(strcmp(result2, "Description2"), 0); 94 | } 95 | 96 | - (void)testConcurrentAccess { 97 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 98 | dispatch_group_t group = dispatch_group_create(); 99 | 100 | TestObject *obj = [[TestObject alloc] init]; 101 | obj.customDescription = @"ConcurrentTest"; 102 | 103 | const char *initialResult = lookup_description_for_address((__bridge void *)obj, [TestObject class]); 104 | XCTAssertNotEqual(initialResult, NULL); 105 | 106 | for (int i = 0; i < 100; i++) { 107 | dispatch_group_async(group, queue, ^{ 108 | const char *result = lookup_description_for_address((__bridge void *)obj, [TestObject class]); 109 | XCTAssertNotEqual(result, NULL); 110 | if (result != NULL) { 111 | XCTAssertEqual(strncmp(result, "ConcurrentTest", strlen("ConcurrentTest")), 0); 112 | } 113 | }); 114 | } 115 | 116 | XCTAssertEqual(dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC)), 0); 117 | } 118 | 119 | - (void)testIMPCacheConsistency { 120 | Class testClass = [TestObject class]; 121 | 122 | for (int i = 0; i < 100; i++) { 123 | TestObject *obj = [[TestObject alloc] init]; 124 | obj.customDescription = [NSString stringWithFormat:@"IMPTest%d", i]; 125 | const char *result = lookup_description_for_address((__bridge void *)obj, testClass); 126 | XCTAssertNotEqual(result, NULL); 127 | XCTAssertTrue(strstr(result, "IMPTest") != NULL); 128 | } 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /src/libobjseeTests/RealizedClassTrackingTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // RealizedClassTrackingTests.m 3 | // libobjseeTests 4 | // 5 | // Created by Ethan Arbuckle on 2/9/25. 6 | // 7 | 8 | #import 9 | #import 10 | #import "realized_class_tracking.h" 11 | 12 | @interface RealizedClassTrackingTests : XCTestCase { 13 | Class _testClass; 14 | } 15 | @end 16 | 17 | @implementation RealizedClassTrackingTests 18 | 19 | - (void)setUp { 20 | [super setUp]; 21 | _testClass = [NSObject class]; 22 | } 23 | 24 | - (void)testNullClassHandling { 25 | kern_return_t result = record_class_encounter(NULL); 26 | XCTAssertEqual(result, KERN_FAILURE); 27 | 28 | result = has_seen_class(NULL); 29 | XCTAssertEqual(result, KERN_FAILURE); 30 | } 31 | 32 | - (void)testBasicClassRecording { 33 | kern_return_t record_result = record_class_encounter(_testClass); 34 | XCTAssertEqual(record_result, KERN_SUCCESS); 35 | 36 | kern_return_t seen_result = has_seen_class(_testClass); 37 | XCTAssertEqual(seen_result, KERN_SUCCESS); 38 | } 39 | 40 | - (void)testUnseenClass { 41 | Class unseenClass = NSClassFromString(@"SomeNonexistentClass"); 42 | kern_return_t result = has_seen_class(unseenClass); 43 | XCTAssertEqual(result, KERN_FAILURE); 44 | } 45 | 46 | - (void)testMultipleClasses { 47 | Class classes[] = { 48 | [NSObject class], 49 | [NSString class], 50 | [NSArray class], 51 | [NSDictionary class], 52 | [NSNumber class] 53 | }; 54 | 55 | for (size_t i = 0; i < sizeof(classes) / sizeof(Class); i++) { 56 | kern_return_t result = record_class_encounter(classes[i]); 57 | XCTAssertEqual(result, KERN_SUCCESS); 58 | } 59 | 60 | for (size_t i = 0; i < sizeof(classes) / sizeof(Class); i++) { 61 | kern_return_t result = has_seen_class(classes[i]); 62 | XCTAssertEqual(result, KERN_SUCCESS); 63 | } 64 | } 65 | 66 | - (void)testConcurrentClassRecording { 67 | dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 68 | dispatch_group_t group = dispatch_group_create(); 69 | 70 | NSArray *testClasses = @[ 71 | [NSObject class], 72 | [NSString class], 73 | [NSArray class], 74 | [NSDictionary class], 75 | [NSNumber class] 76 | ]; 77 | 78 | [testClasses enumerateObjectsUsingBlock:^(Class cls, NSUInteger idx, BOOL *stop) { 79 | dispatch_group_async(group, concurrentQueue, ^{ 80 | kern_return_t result = record_class_encounter(cls); 81 | XCTAssertEqual(result, KERN_SUCCESS); 82 | }); 83 | }]; 84 | 85 | dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 86 | 87 | for (Class cls in testClasses) { 88 | kern_return_t result = has_seen_class(cls); 89 | XCTAssertEqual(result, KERN_SUCCESS); 90 | } 91 | } 92 | 93 | - (void)testCapacityExpansion { 94 | size_t initialCapacity = 1024; 95 | Class *testClasses = (Class *)malloc((initialCapacity + 101) * sizeof(Class)); 96 | size_t classCount = 0; 97 | 98 | @autoreleasepool { 99 | for (size_t i = 0; i <= initialCapacity + 100; i++) { 100 | char className[32]; 101 | snprintf(className, sizeof(className), "TestClass%zu", i); 102 | 103 | Class existingClass = objc_lookUpClass(className); 104 | if (existingClass != NULL) { 105 | objc_disposeClassPair(existingClass); 106 | } 107 | 108 | Class newClass = objc_allocateClassPair([NSObject class], className, 0); 109 | if (newClass == NULL) { 110 | continue; 111 | } 112 | 113 | objc_registerClassPair(newClass); 114 | kern_return_t result = record_class_encounter(newClass); 115 | XCTAssertEqual(result, KERN_SUCCESS); 116 | 117 | testClasses[classCount++] = newClass; 118 | } 119 | 120 | for (size_t i = 0; i < classCount; i++) { 121 | kern_return_t result = has_seen_class(testClasses[i]); 122 | XCTAssertEqual(result, KERN_SUCCESS); 123 | } 124 | 125 | for (size_t i = 0; i < classCount; i++) { 126 | if (testClasses[i] != NULL) { 127 | objc_disposeClassPair(testClasses[i]); 128 | } 129 | } 130 | } 131 | 132 | free(testClasses); 133 | } 134 | 135 | - (void)testReinitialization { 136 | kern_return_t first_init = record_class_encounter(_testClass); 137 | XCTAssertEqual(first_init, KERN_SUCCESS); 138 | 139 | kern_return_t second_init = record_class_encounter(_testClass); 140 | XCTAssertEqual(second_init, KERN_SUCCESS); 141 | } 142 | 143 | - (void)testConcurrentLookups { 144 | kern_return_t record_result = record_class_encounter(_testClass); 145 | XCTAssertEqual(record_result, KERN_SUCCESS); 146 | 147 | dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 148 | dispatch_group_t group = dispatch_group_create(); 149 | 150 | for (int i = 0; i < 1000; i++) { 151 | dispatch_group_async(group, concurrentQueue, ^{ 152 | kern_return_t result = has_seen_class(self->_testClass); 153 | XCTAssertEqual(result, KERN_SUCCESS); 154 | }); 155 | } 156 | 157 | dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 158 | } 159 | 160 | @end 161 | -------------------------------------------------------------------------------- /src/libobjseeTests/SelectorDenyListTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SelectorDenyListTests.m 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 2/9/25. 6 | // 7 | 8 | #import 9 | #import "selector_deny_list.h" 10 | 11 | @interface SelectorDenyListTests : XCTestCase 12 | @end 13 | 14 | @implementation SelectorDenyListTests 15 | 16 | - (void)testNullSelector { 17 | bool result = selector_is_denylisted(NULL); 18 | XCTAssertFalse(result); 19 | } 20 | 21 | - (void)testDotPrefixSelector { 22 | SEL dotSelector = NSSelectorFromString(@".cxx_destruct"); 23 | bool result = selector_is_denylisted(dotSelector); 24 | XCTAssertTrue(result); 25 | } 26 | 27 | - (void)testSPrefixSelector { 28 | SEL sSelector = NSSelectorFromString(@"someMethod"); 29 | bool result = selector_is_denylisted(sSelector); 30 | XCTAssertFalse(result); 31 | } 32 | 33 | - (void)testKnownDenylistedSelectors { 34 | SEL denylistedSelectors[] = { 35 | sel_registerName("isKindOfClass:"), 36 | sel_registerName("zone"), 37 | sel_registerName("release"), 38 | sel_registerName("allocWithZone:"), 39 | sel_registerName("_tryRetain"), 40 | sel_registerName("retainCount"), 41 | sel_registerName("retain"), 42 | sel_registerName("class"), 43 | sel_registerName("_xref_dispose"), 44 | sel_registerName(".cxx_destruct"), 45 | sel_registerName("alloc"), 46 | sel_registerName("autorelease"), 47 | sel_registerName("dealloc"), 48 | sel_registerName("_isDeallocating"), 49 | }; 50 | 51 | for (size_t i = 0; i < sizeof(denylistedSelectors) / sizeof(SEL); i++) { 52 | bool result = selector_is_denylisted(denylistedSelectors[i]); 53 | XCTAssertTrue(result, @"Selector %@ should be denylisted", NSStringFromSelector(denylistedSelectors[i])); 54 | } 55 | } 56 | 57 | - (void)testCommonNonDenylistedSelectors { 58 | SEL allowedSelectors[] = { 59 | sel_registerName("description"), 60 | sel_registerName("init"), 61 | sel_registerName("setObject:forKey:"), 62 | sel_registerName("count"), 63 | sel_registerName("length") 64 | }; 65 | 66 | for (size_t i = 0; i < sizeof(allowedSelectors) / sizeof(SEL); i++) { 67 | bool result = selector_is_denylisted(allowedSelectors[i]); 68 | XCTAssertFalse(result, @"Selector %@ should not be denylisted", NSStringFromSelector(allowedSelectors[i])); 69 | } 70 | } 71 | 72 | - (void)testBinarySearchEdgeCases { 73 | SEL firstInList = sel_registerName("isKindOfClass:"); 74 | bool result = selector_is_denylisted(firstInList); 75 | XCTAssertTrue(result); 76 | 77 | SEL lastInList = sel_registerName("_isDeallocating"); 78 | result = selector_is_denylisted(lastInList); 79 | XCTAssertTrue(result); 80 | } 81 | 82 | - (void)testHashCollisionHandling { 83 | char selectorBuffer[256]; 84 | for (uint32_t i = 0; i < 1000; i++) { 85 | snprintf(selectorBuffer, sizeof(selectorBuffer), "test_method_%u", i); 86 | SEL testSelector = sel_registerName(selectorBuffer); 87 | selector_is_denylisted(testSelector); 88 | } 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /src/libobjseeTests/StructDecoderTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // StructDecoderTests.m 3 | // libobjseeTests 4 | // 5 | // Created by Ethan Arbuckle on 1/11/25. 6 | // 7 | 8 | #import 9 | #import "encoding_description.h" 10 | 11 | @interface StructDecoderTests : XCTestCase 12 | @end 13 | 14 | @implementation StructDecoderTests 15 | 16 | - (void)setUp { 17 | [super setUp]; 18 | } 19 | 20 | - (void)tearDown { 21 | [super tearDown]; 22 | } 23 | 24 | - (void)testBasicTypes { 25 | XCTAssertEqualObjects(@"int", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("i")]); 26 | XCTAssertEqualObjects(@"char", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("c")]); 27 | XCTAssertEqualObjects(@"long", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("l")]); 28 | XCTAssertEqualObjects(@"float", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("f")]); 29 | XCTAssertEqualObjects(@"double", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("d")]); 30 | 31 | XCTAssertEqualObjects(@"unsigned int", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("I")]); 32 | XCTAssertEqualObjects(@"unsigned char", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("C")]); 33 | XCTAssertEqualObjects(@"unsigned long", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("L")]); 34 | 35 | XCTAssertEqualObjects(@"id", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("@")]); 36 | XCTAssertEqualObjects(@"Class", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("#")]); 37 | XCTAssertEqualObjects(@"SEL", [NSString stringWithUTF8String:get_struct_description_from_type_encoding(":")]); 38 | } 39 | 40 | - (void)testPointerTypes { 41 | XCTAssertEqualObjects(@"char *", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("*")]); 42 | XCTAssertEqualObjects(@"int *", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("^i")]); 43 | XCTAssertEqualObjects(@"double *", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("^d")]); 44 | XCTAssertEqualObjects(@"const int *", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("^ri")]); 45 | } 46 | 47 | - (void)testSimpleStructs { 48 | XCTAssertEqualObjects(@"CGPoint { double, double }", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("{CGPoint=dd}")]); 49 | XCTAssertEqualObjects(@"CGSize { double, double }", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("{CGSize=dd}")]); 50 | XCTAssertEqualObjects(@"struct { int, char }", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("{?=ic}")]); 51 | } 52 | 53 | - (void)testComplexStructs { 54 | XCTAssertEqualObjects(@"ComplexStruct { int, char *, double }", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("{ComplexStruct=i*d}")]); 55 | XCTAssertEqualObjects(@"OuterStruct { int, struct { double, double }, char }", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("{OuterStruct=i{?=dd}c}")]); 56 | XCTAssertEqualObjects(@"ConstStruct { const int, double }", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("{ConstStruct=rid}")]); 57 | XCTAssertEqualObjects(@"CGRect { CGPoint { double, double }, CGSize { double, double } }", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("{CGRect={CGPoint=dd}{CGSize=dd}}")]); 58 | XCTAssertEqualObjects(@"struct { long long, long long, double, long long, long long, long long, long long, long long, id, CGSize { double, double }, long long, long long, long long }", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("{?=qqdqqqqq@{CGSize=dd}qqq}")]); 59 | } 60 | 61 | - (void)testEdgeCases { 62 | XCTAssertEqualObjects(@"invalid_encoding", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("")]); 63 | XCTAssertEqualObjects(@"invalid_encoding", [NSString stringWithUTF8String:get_struct_description_from_type_encoding(NULL)]); 64 | XCTAssertEqualObjects(@"unknown_type", [NSString stringWithUTF8String:get_struct_description_from_type_encoding("x")]); 65 | XCTAssertNotNil([NSString stringWithUTF8String:get_struct_description_from_type_encoding("{CGPoint=d")]); 66 | } 67 | 68 | - (void)testMemoryManagement { 69 | 70 | for (int i = 0; i < 1000; i++) { 71 | char *result = get_struct_description_from_type_encoding("{CGPoint=dd}"); 72 | XCTAssertNotNil([NSString stringWithUTF8String:result]); 73 | free(result); 74 | } 75 | 76 | NSMutableString *largeStruct = [NSMutableString stringWithString:@"{LargeStruct="]; 77 | for (int i = 0; i < 100; i++) { 78 | [largeStruct appendString:@"i"]; 79 | } 80 | [largeStruct appendString:@"}"]; 81 | 82 | char *result = get_struct_description_from_type_encoding([largeStruct UTF8String]); 83 | XCTAssertNotNil([NSString stringWithUTF8String:result]); 84 | free(result); 85 | } 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /src/libobjseeTests/libobjseeTests.xctestplan: -------------------------------------------------------------------------------- 1 | { 2 | "configurations" : [ 3 | { 4 | "id" : "FD8479FC-1A51-47E4-A320-380168651C8B", 5 | "name" : "Configuration 1", 6 | "options" : { 7 | 8 | } 9 | } 10 | ], 11 | "defaultOptions" : { 12 | "uiTestingScreenshotsLifetime" : "keepNever" 13 | }, 14 | "testTargets" : [ 15 | { 16 | "parallelizable" : true, 17 | "target" : { 18 | "containerPath" : "container:objsee.xcodeproj", 19 | "identifier" : "5FF9EFE52D3321A000BCFBA9", 20 | "name" : "libobjseeTests" 21 | } 22 | } 23 | ], 24 | "version" : 1 25 | } 26 | -------------------------------------------------------------------------------- /src/objsee-cli/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS := arm64 2 | TARGET := iphone:clang:latest:16.1 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | INCLUDE_DIRS := $(shell find . ../libobjsee -type d) 7 | INCLUDE_FLAGS := $(INCLUDE_DIRS:%=-I%) 8 | 9 | TOOL_NAME = objsee-cli 10 | objsee-cli_INSTALL_PATH = /usr/local/bin 11 | objsee-cli_FILES += $(shell find . -type f \( -name '*.c' -o -name '*.m' \)) $(shell find ../libobjsee -type f \( -name '*.c' -o -name '*.m' \)) $(wildcard ../../dependencies/kat/*.c) 12 | objsee-cli_CFLAGS += -fobjc-arc 13 | objsee-cli_CFLAGS += $(INCLUDE_FLAGS) 14 | objsee-cli_CFLAGS += -I./../../dependencies/include 15 | objsee-cli_CFLAGS += -I./../../dependencies/kat 16 | objsee-cli_CFLAGS += -Wno-unused-but-set-variable 17 | objsee-cli_CFLAGS += -DOBJSEE_CLI_VERSION=\"$(PACKAGE_VERSION)\" 18 | objsee-cli_CFLAGS += -DOBJSEE_LIB_VERSION=\"$(PACKAGE_VERSION)\" 19 | objsee-cli_LDFLAGS += -L../../dependencies/libs/ 20 | objsee-cli_LDFLAGS += -ljson-c-ios 21 | objsee-cli_LDFLAGS += -lncursesw-ios 22 | objsee-cli_LDFLAGS += -lcapstone-ios 23 | objsee-cli_CODESIGN_FLAGS += -S./objsee-entitlements.xml 24 | include $(THEOS_MAKE_PATH)/tool.mk -------------------------------------------------------------------------------- /src/objsee-cli/app_launching.h: -------------------------------------------------------------------------------- 1 | // 2 | // app_launching.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/17/25. 6 | // 7 | 8 | #ifndef app_launching_h 9 | #define app_launching_h 10 | 11 | #include 12 | #include "cli_args.h" 13 | 14 | extern const char *OBJSEE_LIBRARY_PATH; 15 | 16 | /** 17 | * Launches an app with a given bundle ID 18 | * @param bundleID The bundle ID of the app to launch 19 | * @return KERN_SUCCESS on success, an error code on failure 20 | */ 21 | kern_return_t launch_app_with_encoded_tracer_config(NSString *bundleID, NSString *configString); 22 | 23 | /** 24 | * Terminates an app with a given bundle ID 25 | * @param bundleID The bundle ID of the app to terminate 26 | * @return KERN_SUCCESS on success, an error code on failure 27 | */ 28 | kern_return_t terminate_app_if_running(NSString *bundleID); 29 | 30 | /** 31 | * Waits for launch completion of an app with a given bundle ID 32 | * @param bundleID The bundle ID of the app to wait for 33 | * @param completion The block to call when the app is launched 34 | */ 35 | void on_process_launch(NSString *bundleID, void (^completion)(pid_t pid)); 36 | 37 | /** 38 | * Finds a free socket port to use for the tracer transport 39 | * @return The port number 40 | */ 41 | int find_free_socket_port(void); 42 | 43 | /** 44 | * Spawns a process with a given config string 45 | * @param options The CLI options 46 | * @param config The tracer config 47 | * @return KERN_SUCCESS on success, an error code on failure 48 | */ 49 | kern_return_t spawn_process(cli_options_t *options, tracer_config_t config); 50 | 51 | 52 | #endif /* app_launching_h */ 53 | -------------------------------------------------------------------------------- /src/objsee-cli/cli_args.h: -------------------------------------------------------------------------------- 1 | // 2 | // cli_args.h 3 | // cli 4 | // 5 | // Created by Ethan Arbuckle on 1/17/25. 6 | // 7 | 8 | #ifndef cli_args_h 9 | #define cli_args_h 10 | 11 | #include 12 | #include "tracer_types.h" 13 | 14 | typedef struct { 15 | const char *bundle_id; 16 | const char *file_path; 17 | pid_t pid; 18 | bool tui_mode; 19 | bool show_help; 20 | bool show_version; 21 | bool no_color; 22 | bool run_in_simulator; 23 | bool server_only; 24 | int argc; 25 | char **argv; 26 | } cli_options_t; 27 | 28 | /** 29 | * Parses CLI arguments into a struct 30 | * @param argc The number of arguments 31 | * @param argv The arguments 32 | * @param options The options struct to populate 33 | * @param config The config struct to populate 34 | * @return 0 on success, an error code on failure 35 | */ 36 | int parse_cli_arguments(int argc, char *argv[], cli_options_t *options, tracer_config_t *config); 37 | 38 | /** 39 | * Applies default values to a config struct 40 | * @param config The config struct to populate 41 | * @return 0 on success, an error code on failure 42 | */ 43 | int apply_defaults_to_config(tracer_config_t *config); 44 | 45 | #endif /* cli_args_h */ 46 | -------------------------------------------------------------------------------- /src/objsee-cli/cli_args.m: -------------------------------------------------------------------------------- 1 | // 2 | // cli_args.m 3 | // cli 4 | // 5 | // Created by Ethan Arbuckle on 1/17/25. 6 | // 7 | 8 | #include 9 | #include 10 | #include "app_launching.h" 11 | #include "cli_args.h" 12 | 13 | static pid_t pid_from_hint(const char *hint) { 14 | if (hint == NULL) { 15 | return -1; 16 | } 17 | 18 | static dispatch_once_t onceToken; 19 | static void *pidFromHint = NULL; 20 | dispatch_once(&onceToken, ^{ 21 | void *symbolication_handle = dlopen("/System/Library/PrivateFrameworks/Symbolication.framework/Symbolication", 9); 22 | if (symbolication_handle) { 23 | pidFromHint = dlsym(symbolication_handle, "pidFromHint"); 24 | } 25 | }); 26 | 27 | if (pidFromHint == NULL) { 28 | printf("Failed to resolve pidFromHint()\n"); 29 | return -1; 30 | } 31 | 32 | return ((pid_t (*)(NSString *))pidFromHint)([NSString stringWithUTF8String:hint]); 33 | } 34 | 35 | int parse_cli_arguments(int argc, char *argv[], cli_options_t *options, tracer_config_t *config) { 36 | memset(options, 0, sizeof(cli_options_t)); 37 | options->argc = argc; 38 | options->argv = argv; 39 | 40 | for (int i = 1; i < argc; i++) { 41 | if (strcmp(argv[i], "-h") == 0) { 42 | options->show_help = true; 43 | return 0; 44 | } 45 | 46 | if (strcmp(argv[i], "--help") == 0) { 47 | options->show_help = true; 48 | options->show_version = true; 49 | return 0; 50 | } 51 | 52 | if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) { 53 | options->show_version = true; 54 | return 0; 55 | } 56 | 57 | if (strcmp(argv[i], "--nocolor") == 0) { 58 | config->format.include_colors = false; 59 | continue; 60 | } 61 | 62 | if (strcmp(argv[i], "-T") == 0) { 63 | options->tui_mode = true; 64 | continue; 65 | } 66 | 67 | if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) { 68 | options->pid = pid_from_hint(argv[i + 1]); 69 | i++; 70 | continue; 71 | } 72 | 73 | if (strcmp(argv[i], "--sim") == 0) { 74 | options->run_in_simulator = true; 75 | continue; 76 | } 77 | 78 | if (strcmp(argv[i], "--server") == 0) { 79 | options->server_only = true; 80 | continue; 81 | } 82 | 83 | // arg verbosity: -A0, -A1, -A2, -A3 84 | if (argv[i][0] == '-' && argv[i][1] == 'A' && argv[i][2] >= '0' && argv[i][2] <= '3') { 85 | config->format.args = argv[i][2] - '0'; 86 | continue; 87 | } 88 | 89 | if (argv[i][0] == '-' && i + 1 < argc) { 90 | if (config->filter_count >= TRACER_MAX_FILTERS) { 91 | printf("Error: Too many filters (max is %d)\n", TRACER_MAX_FILTERS); 92 | return -1; 93 | } 94 | 95 | int current = config->filter_count; 96 | const char *pattern = argv[i + 1]; 97 | 98 | switch (argv[i][1]) { 99 | case 'c': 100 | config->filters[current].class_pattern = pattern; 101 | config->filters[current].exclude = false; 102 | break; 103 | case 'C': 104 | config->filters[current].class_pattern = pattern; 105 | config->filters[current].exclude = true; 106 | break; 107 | case 'm': 108 | config->filters[current].method_pattern = pattern; 109 | config->filters[current].exclude = false; 110 | break; 111 | case 'M': 112 | config->filters[current].method_pattern = pattern; 113 | config->filters[current].exclude = true; 114 | break; 115 | case 'i': 116 | config->filters[current].image_pattern = pattern; 117 | config->filters[current].exclude = false; 118 | break; 119 | default: 120 | printf("Error: Unknown option '%s'\n", argv[i]); 121 | return -1; 122 | } 123 | 124 | config->filter_count++; 125 | i++; 126 | continue; 127 | } 128 | 129 | if ((options->file_path == NULL || options->bundle_id == NULL) && argv[i][0] != '-') { 130 | if (options->file_path == NULL && access(argv[i], F_OK) != -1) { 131 | options->file_path = argv[i]; 132 | continue; 133 | } 134 | 135 | options->bundle_id = argv[i]; 136 | } 137 | else { 138 | // Allow arbitrary args if we're launching an executable 139 | if (options->file_path != NULL) { 140 | continue; 141 | } 142 | 143 | printf("Error: Unexpected argument '%s'\n", argv[i]); 144 | return -1; 145 | } 146 | } 147 | 148 | return 0; 149 | } 150 | 151 | int apply_defaults_to_config(tracer_config_t *config) { 152 | config->transport_config.host = "127.0.0.1"; 153 | config->transport_config.port = find_free_socket_port(); 154 | config->transport = TRACER_TRANSPORT_SOCKET; 155 | if (config->transport_config.port == -1) { 156 | return -1; 157 | } 158 | 159 | config->format = (tracer_format_options_t){ 160 | .include_formatted_trace = true, 161 | .include_event_json = false, 162 | .output_as_json = true, 163 | .include_colors = true, 164 | .include_thread_id = true, 165 | .include_indents = true, 166 | .indent_char = " ", 167 | .include_indent_separators = true, 168 | .indent_separator_char = "|", 169 | .variable_separator_spacing = false, 170 | .static_separator_spacing = 2, 171 | .include_newline_in_formatted_trace = false, 172 | .args = TRACER_ARG_FORMAT_CLASS, 173 | }; 174 | 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /src/objsee-cli/exception_handling/crash_handler.h: -------------------------------------------------------------------------------- 1 | // 2 | // crash_handler.h 3 | // cli 4 | // 5 | // Created by Ethan Arbuckle on 12/30/24. 6 | // 7 | 8 | #ifndef crash_handler_h 9 | #define crash_handler_h 10 | 11 | #include 12 | 13 | void setup_exception_handler_on_process(pid_t traced_app_pid); 14 | 15 | #endif /* crash_handler_h */ 16 | -------------------------------------------------------------------------------- /src/objsee-cli/exception_handling/symbolication.c: -------------------------------------------------------------------------------- 1 | // 2 | // symbolication.c 3 | // cli 4 | // 5 | // Created by Ethan Arbuckle on 1/17/25. 6 | // 7 | 8 | #include 9 | #include 10 | #include "symbolication.h" 11 | 12 | static struct { 13 | bool initialized; 14 | CSSymbolicatorRef (*CreateWithTaskFlagsAndNotification)(task_t, uint32_t, void *); 15 | CSSymbolOwnerRef (*GetSymbolOwnerWithAddressAtTime)(CSSymbolicatorRef, vm_address_t, uint64_t); 16 | CSSymbolOwnerRef (*GetSymbolOwnerWithNameAtTime)(CSSymbolicatorRef, const char *, uint64_t); 17 | CSSymbolRef (*GetSymbolWithName)(CSSymbolicatorRef, const char *, uint64_t); 18 | CSSymbolRef (*GetSymbolWithAddress)(CSSymbolOwnerRef, vm_address_t); 19 | CSSymbolRef (*GetSymbolFromOwnerWithName)(CSSymbolOwnerRef, const char *); 20 | Boolean (*IsNull)(CSTypeRef); 21 | const char *(*GetSymbolName)(CSSymbolRef); 22 | const char *(*GetSymbolOwnerPath)(CSSymbolRef); 23 | CSRange (*GetSymbolRange)(CSSymbolRef); 24 | int (*GetSymbolOwnerCountAtTime)(CSSymbolicatorRef, uint64_t); 25 | int (*ForEachSymbolAtTime)(CSSymbolicatorRef, uint64_t, void (^)(CSSymbolRef)); 26 | int (*ForEachSymbolOwnerAtTime)(CSSymbolicatorRef, uint64_t, void (^)(CSSymbolOwnerRef)); 27 | } CS; 28 | 29 | CSSymbolicatorRef create_symbolicator_with_task(task_t task) { 30 | if (task == TASK_NULL) { 31 | return CSNULL; 32 | } 33 | 34 | return CS.CreateWithTaskFlagsAndNotification(task, 1, NULL); 35 | } 36 | 37 | CSSymbolOwnerRef get_symbol_owner(CSSymbolicatorRef symbolicator, uint64_t address) { 38 | return CS.GetSymbolOwnerWithAddressAtTime(symbolicator, address, 0x80000000u); 39 | } 40 | 41 | CSSymbolOwnerRef get_symbol_owner_for_name(CSSymbolicatorRef symbolicator, const char *name) { 42 | if (name == NULL) { 43 | return CSNULL; 44 | } 45 | return CS.GetSymbolOwnerWithNameAtTime(symbolicator, name, CS_NOW); 46 | } 47 | 48 | CSSymbolRef get_symbol_for_name(CSSymbolicatorRef symbolicator, const char *name) { 49 | return CS.GetSymbolWithName(symbolicator, name, CS_NOW); 50 | } 51 | 52 | CSSymbolRef get_symbol_at_address(CSSymbolOwnerRef symbol_owner, uint64_t address) { 53 | if (CS.IsNull(symbol_owner)) { 54 | return CSNULL; 55 | } 56 | return CS.GetSymbolWithAddress(symbol_owner, address); 57 | } 58 | 59 | CSSymbolRef get_symbol_from_owner_with_name(CSSymbolOwnerRef symbol_owner, const char *name) { 60 | if (CS.IsNull(symbol_owner)) { 61 | return CSNULL; 62 | } 63 | return CS.GetSymbolFromOwnerWithName(symbol_owner, name); 64 | } 65 | 66 | CSRange get_range_for_symbol(CSSymbolRef symbol) { 67 | return CS.GetSymbolRange(symbol); 68 | } 69 | 70 | const char *get_image_path_for_symbol_owner(CSSymbolOwnerRef symbol_owner) { 71 | return CS.GetSymbolOwnerPath(symbol_owner); 72 | } 73 | 74 | const char *get_name_for_symbol(CSSymbolRef symbol) { 75 | return CS.GetSymbolName(symbol); 76 | } 77 | 78 | const char *get_name_for_symbol_at_address(CSSymbolicatorRef symbolicator, uint64_t address) { 79 | CSSymbolOwnerRef symbol_owner = get_symbol_owner(symbolicator, address); 80 | if (CS.IsNull(symbol_owner)) { 81 | return NULL; 82 | } 83 | 84 | CSSymbolRef symbol = get_symbol_at_address(symbol_owner, address); 85 | if (CS.IsNull(symbol)) { 86 | return NULL; 87 | } 88 | 89 | return get_name_for_symbol(symbol); 90 | } 91 | 92 | bool cs_isnull(CSTypeRef ref) { 93 | return CS.IsNull(ref); 94 | } 95 | 96 | int get_symbol_owner_count(CSSymbolicatorRef symbolicator) { 97 | return CS.GetSymbolOwnerCountAtTime(symbolicator, CS_NOW); 98 | } 99 | 100 | void for_each_symbol(CSSymbolicatorRef symbolicator, void (^handler)(CSSymbolRef)) { 101 | CS.ForEachSymbolAtTime(symbolicator, CS_NOW, ^(CSSymbolRef symbol) { 102 | handler(symbol); 103 | }); 104 | } 105 | 106 | void for_each_symbol_owner(CSSymbolicatorRef symbolicator, void (^handler)(CSSymbolOwnerRef)) { 107 | CS.ForEachSymbolOwnerAtTime(symbolicator, CS_NOW, ^(CSSymbolOwnerRef owner) { 108 | handler(owner); 109 | }); 110 | } 111 | 112 | bool symbolication_initialized(void) { 113 | return CS.initialized; 114 | } 115 | 116 | __attribute__((constructor)) 117 | static kern_return_t init_core_symbolication(void) { 118 | 119 | static dispatch_once_t onceToken; 120 | dispatch_once(&onceToken, ^{ 121 | CS.initialized = false; 122 | void *core_symbolication_handle = dlopen("/System/Library/PrivateFrameworks/CoreSymbolication.framework/CoreSymbolication", RTLD_NOW); 123 | CS.CreateWithTaskFlagsAndNotification = dlsym(core_symbolication_handle, "CSSymbolicatorCreateWithTaskFlagsAndNotification"); 124 | CS.GetSymbolOwnerWithAddressAtTime = dlsym(core_symbolication_handle, "CSSymbolicatorGetSymbolOwnerWithAddressAtTime"); 125 | CS.GetSymbolOwnerWithNameAtTime = dlsym(core_symbolication_handle, "CSSymbolicatorGetSymbolOwnerWithNameAtTime"); 126 | CS.GetSymbolWithName = dlsym(core_symbolication_handle, "CSSymbolicatorGetSymbolWithNameAtTime"); 127 | CS.GetSymbolWithAddress = dlsym(core_symbolication_handle, "CSSymbolOwnerGetSymbolWithAddress"); 128 | CS.IsNull = dlsym(core_symbolication_handle, "CSIsNull"); 129 | CS.GetSymbolName = dlsym(core_symbolication_handle, "CSSymbolGetName"); 130 | CS.GetSymbolOwnerPath = dlsym(core_symbolication_handle, "CSSymbolOwnerGetPath"); 131 | CS.GetSymbolRange = dlsym(core_symbolication_handle, "CSSymbolGetRange"); 132 | CS.GetSymbolOwnerCountAtTime = dlsym(core_symbolication_handle, "CSSymbolicatorGetSymbolOwnerCountAtTime"); 133 | CS.ForEachSymbolAtTime = dlsym(core_symbolication_handle, "CSSymbolicatorForeachSymbolAtTime"); 134 | CS.ForEachSymbolOwnerAtTime = dlsym(core_symbolication_handle, "CSSymbolicatorForeachSymbolOwnerAtTime"); 135 | CS.GetSymbolFromOwnerWithName = dlsym(core_symbolication_handle, "CSSymbolOwnerGetSymbolWithName"); 136 | 137 | for (size_t i = 1; i < sizeof(CS) / sizeof(void *); i++) { 138 | if (((void **)(&CS))[i] == NULL) { 139 | CS.initialized = false; 140 | os_log(OS_LOG_DEFAULT, "Failed to locate symbol %lu\n", i); 141 | return; 142 | } 143 | } 144 | 145 | CS.initialized = true; 146 | }); 147 | 148 | return CS.initialized ? KERN_SUCCESS : KERN_FAILURE; 149 | } 150 | -------------------------------------------------------------------------------- /src/objsee-cli/exception_handling/symbolication.h: -------------------------------------------------------------------------------- 1 | // 2 | // symbolication.h 3 | // cli 4 | // 5 | // Created by Ethan Arbuckle on 1/17/25. 6 | // 7 | 8 | #ifndef symbolication_h 9 | #define symbolication_h 10 | 11 | #include 12 | 13 | #define CS_NOW 0x80000000u 14 | #define CSNULL (CSTypeRef){0, 0} 15 | 16 | struct sCSTypeRef { 17 | void *csCppData; 18 | void *csCppObj; 19 | }; 20 | 21 | typedef struct sCSTypeRef CSTypeRef; 22 | typedef CSTypeRef CSSymbolicatorRef; 23 | typedef CSTypeRef CSSymbolOwnerRef; 24 | typedef CSTypeRef CSSymbolRef; 25 | 26 | struct sCSRange { 27 | unsigned long long location; 28 | unsigned long long length; 29 | }; 30 | typedef struct sCSRange CSRange; 31 | 32 | CSSymbolicatorRef create_symbolicator_with_task(task_t task); 33 | CSSymbolOwnerRef get_symbol_owner(CSSymbolicatorRef symbolicator, uint64_t address); 34 | CSSymbolOwnerRef get_symbol_owner_for_name(CSSymbolicatorRef symbolicator, const char *name); 35 | CSSymbolRef get_symbol_for_name(CSSymbolicatorRef symbolicator, const char *name); 36 | CSSymbolRef get_symbol_at_address(CSSymbolOwnerRef symbol_owner, uint64_t address); 37 | CSSymbolRef get_symbol_from_owner_with_name(CSSymbolOwnerRef symbol_owner, const char *name); 38 | CSRange get_range_for_symbol(CSSymbolRef symbol); 39 | const char *get_image_path_for_symbol_owner(CSSymbolOwnerRef symbol_owner); 40 | const char *get_name_for_symbol(CSSymbolRef symbol); 41 | const char *get_name_for_symbol_at_address(CSSymbolicatorRef symbolicator, uint64_t address); 42 | void for_each_symbol(CSSymbolicatorRef symbolicator, void (^handler)(CSSymbolRef)); 43 | void for_each_symbol_owner(CSSymbolicatorRef symbolicator, void (^handler)(CSSymbolOwnerRef)); 44 | int get_symbol_owner_count(CSSymbolicatorRef symbolicator); 45 | bool cs_isnull(CSTypeRef ref); 46 | bool symbolication_initialized(void); 47 | 48 | #endif /* symbolication_h */ 49 | -------------------------------------------------------------------------------- /src/objsee-cli/injector/dylib_injector.h: -------------------------------------------------------------------------------- 1 | // 2 | // dylib_injector.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/16/25. 6 | // 7 | 8 | #ifndef dylib_injector_h 9 | #define dylib_injector_h 10 | 11 | #include 12 | 13 | /** 14 | * Calls a function in a remote process 15 | * @param function_address The address of the function to call 16 | * @param pid The process ID to call the function in 17 | * @return KERN_SUCCESS on success, an error code on failure 18 | */ 19 | kern_return_t call_remote_function_with_string(uint64_t function_address, const char *string_arg, pid_t pid); 20 | 21 | /** 22 | * Injects a dylib into a remote process 23 | * @param dylib_path The path to the dylib to inject 24 | * @param pid The process ID to inject into 25 | * @return KERN_SUCCESS on success, an error code on failure 26 | */ 27 | kern_return_t inject_dylib_into_pid(const char *dylib_path, int pid); 28 | 29 | /** 30 | * Get the address of a function in a remote process 31 | * @param function_name The name of the function to find 32 | * @param image_filter The name of the image to search in. If NULL, all images will be searched 33 | * @param pid The process ID to search in 34 | * @return The address of the function in the remote process 35 | */ 36 | uint64_t get_function_address_in_pid(const char *function_name, const char *image_filter, int pid); 37 | 38 | #endif /* dylib_injector_h */ 39 | -------------------------------------------------------------------------------- /src/objsee-cli/objsee-entitlements.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | platform-application 6 | 7 | get-task-allow 8 | 9 | com.apple.system-task-ports 10 | 11 | task_for_pid-allow 12 | 13 | com.apple.springboard.launchapplications 14 | 15 | com.apple.frontboard.launchapplications 16 | 17 | com.apple.private.MobileContainerManager.allowed 18 | 19 | com.apple.multitasking.termination 20 | 21 | com.apple.private.security.container-required 22 | 23 | com.apple.frontboard.debugapplications 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/objsee-cli/simulator/sim_launching.h: -------------------------------------------------------------------------------- 1 | // 2 | // sim_launching.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/18/25. 6 | // 7 | 8 | #ifndef sim_launching_h 9 | #define sim_launching_h 10 | 11 | #include 12 | 13 | /** 14 | * Get the UUID of the first booted simulator encountered 15 | * @return The UUID of the simulator, or nil on failure or no simulators booted 16 | */ 17 | NSString *first_booted_simulator_uuid(void); 18 | 19 | /** 20 | * Launch an app for tracing in the simulator with a given bundle ID 21 | * @param simulatorUUID The UUID of the simulator to launch the app in 22 | * @param bundleID The bundle ID of the app to launch 23 | * @oaram configString The encoded tracer config to use 24 | * @return KERN_SUCCESS on success, an error code on failure 25 | */ 26 | kern_return_t launch_simulator_app_with_encoded_tracer_config(NSString *simulatorUUID, NSString *bundleID, NSString *configString); 27 | 28 | #endif /* sim_launching_h */ 29 | -------------------------------------------------------------------------------- /src/objsee-cli/simulator/sim_launching.m: -------------------------------------------------------------------------------- 1 | // 2 | // sim_launching.m 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/18/25. 6 | // 7 | 8 | #include 9 | #include 10 | #include "app_launching.h" 11 | 12 | 13 | static NSString *run_command(NSArray *command, NSDictionary *environment, BOOL waitUntilExit) { 14 | NSPipe *pipe = [NSPipe pipe]; 15 | NSFileHandle *file = pipe.fileHandleForReading; 16 | 17 | id task = [[objc_getClass("NSTask") alloc] init]; 18 | ((void (*)(id, SEL, id))objc_msgSend)(task, NSSelectorFromString(@"setLaunchPath:"), @"/usr/bin/env"); 19 | ((void (*)(id, SEL, id))objc_msgSend)(task, NSSelectorFromString(@"setArguments:"), command); 20 | ((void (*)(id, SEL, id))objc_msgSend)(task, NSSelectorFromString(@"setStandardOutput:"), pipe); 21 | ((void (*)(id, SEL, id))objc_msgSend)(task, NSSelectorFromString(@"setStandardError:"), pipe); 22 | if (environment) { 23 | ((void (*)(id, SEL, id))objc_msgSend)(task, NSSelectorFromString(@"setEnvironment:"), environment); 24 | } 25 | 26 | ((void (*)(id, SEL))objc_msgSend)(task, NSSelectorFromString(@"launch")); 27 | if (waitUntilExit) { 28 | ((void (*)(id, SEL))objc_msgSend)(task, NSSelectorFromString(@"waitUntilExit")); 29 | NSData *data = [file readDataToEndOfFile]; 30 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 31 | } 32 | 33 | return nil; 34 | } 35 | 36 | NSString *first_booted_simulator_uuid(void) { 37 | // Find the first booted simulator and return its UUID 38 | NSArray *command = @[@"xcrun", @"simctl", @"list", @"--json", @"-e", @"devices"]; 39 | NSString *output = run_command(command, nil, YES); 40 | NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[output dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; 41 | for (NSArray *simRuntime in json[@"devices"]) { 42 | for (NSDictionary *simDevice in json[@"devices"][simRuntime]) { 43 | if ([simDevice[@"state"] isEqualToString:@"Booted"]) { 44 | return simDevice[@"udid"]; 45 | } 46 | } 47 | } 48 | 49 | return nil; 50 | } 51 | 52 | kern_return_t launch_simulator_app_with_encoded_tracer_config(NSString *simulatorUUID, NSString *bundleID, NSString *configString) { 53 | NSArray *command = @[@"xcrun", @"simctl", @"launch", simulatorUUID, bundleID]; 54 | NSMutableDictionary *environment = [NSMutableDictionary dictionaryWithDictionary:[[NSProcessInfo processInfo] environment]]; 55 | 56 | // Inject the tracer library with DYLD_INSERT_LIBRARIES 57 | environment[@"SIMCTL_CHILD_DYLD_INSERT_LIBRARIES"] = [NSString stringWithUTF8String:OBJSEE_LIBRARY_PATH]; 58 | // Provide the tracing config as an env var 59 | environment[@"SIMCTL_CHILD_OBJSEE_CONFIG"] = configString; 60 | 61 | // Launch the app in the simulator 62 | run_command(command, environment, NO); 63 | 64 | dispatch_semaphore_t sem = dispatch_semaphore_create(0); 65 | on_process_launch(bundleID, ^(pid_t pid) { 66 | if (pid > 0) { 67 | printf("App launched with PID: %d\n", pid); 68 | } 69 | dispatch_semaphore_signal(sem); 70 | }); 71 | 72 | dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 73 | return KERN_SUCCESS; 74 | } 75 | -------------------------------------------------------------------------------- /src/objsee-cli/simulator/tmpfs_overlay.h: -------------------------------------------------------------------------------- 1 | // 2 | // tmpfs_overlay.h 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/31/25. 6 | // 7 | 8 | #include 9 | 10 | 11 | 12 | int make_running_simulator_runtime_readwrite(void); 13 | -------------------------------------------------------------------------------- /src/objsee-cli/simulator/tmpfs_overlay.m: -------------------------------------------------------------------------------- 1 | // 2 | // tmpfs_overlay.m 3 | // objsee 4 | // 5 | // Created by Ethan Arbuckle on 1/31/25. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 14 | 15 | #include 16 | #include 17 | 18 | static int _system(const char *cmd) { 19 | static dispatch_once_t onceToken; 20 | static void *system_func = NULL; 21 | dispatch_once(&onceToken, ^{ 22 | system_func = dlsym(RTLD_DEFAULT, "system"); 23 | }); 24 | 25 | if (system_func == NULL) { 26 | return -1; 27 | } 28 | 29 | return ((int (*)(const char *))system_func)(cmd); 30 | } 31 | 32 | static bool is_tmpfs_mount(const char *path) { 33 | struct statfs fs; 34 | if (statfs(path, &fs) < 0) { 35 | return false; 36 | } 37 | 38 | return strstr(fs.f_fstypename, "tmpfs") != NULL; 39 | } 40 | 41 | pid_t find_pid_of_running_sim_launchd(void) { 42 | struct kinfo_proc *procs = NULL; 43 | size_t procs_size = 0; 44 | int num_procs = 0; 45 | int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; 46 | 47 | if (sysctl(mib, 4, NULL, &procs_size, NULL, 0) < 0) { 48 | return -1; 49 | } 50 | 51 | procs = malloc(procs_size); 52 | if (sysctl(mib, 4, procs, &procs_size, NULL, 0) < 0) { 53 | free(procs); 54 | return -1; 55 | } 56 | 57 | num_procs = (int)procs_size / sizeof(struct kinfo_proc); 58 | for (int i = 0; i < num_procs; i++) { 59 | struct kinfo_proc *proc = &procs[i]; 60 | if (strstr(proc->kp_proc.p_comm, "launchd_sim") != NULL) { 61 | printf("Found launchd_sim with pid %d\n", proc->kp_proc.p_pid); 62 | free(procs); 63 | return proc->kp_proc.p_pid; 64 | } 65 | } 66 | 67 | free(procs); 68 | return 0; 69 | } 70 | 71 | static int create_overlay_on_path(const char *path, bool copy_contents) { 72 | if (is_tmpfs_mount(path)) { 73 | printf("Path is already a tmpfs mount: %s\n", path); 74 | return 0; 75 | } 76 | 77 | const char *backup_path = NULL; 78 | if (copy_contents) { 79 | char template[PATH_MAX]; 80 | snprintf(template, sizeof(template), "/tmp/ios_backup.XXXXXX"); 81 | backup_path = mkdtemp(template); 82 | if (backup_path == NULL) { 83 | printf("Failed to create temporary directory\n"); 84 | return -1; 85 | } 86 | 87 | char cp_cmd[256]; 88 | snprintf(cp_cmd, sizeof(cp_cmd), "cp -R '%s'/* '%s'", path, backup_path); 89 | if (_system(cp_cmd) != 0) { 90 | printf("Failed to copy contents from %s to %s\n", path, backup_path); 91 | return -1; 92 | } 93 | } 94 | 95 | char mount_cmd[256]; 96 | snprintf(mount_cmd, sizeof(mount_cmd), "mount_tmpfs '%s'", path); 97 | if (_system(mount_cmd) != 0) { 98 | printf("Failed to mount tmpfs on %s\n", path); 99 | return -1; 100 | } 101 | 102 | if (backup_path) { 103 | char cp_cmd[256]; 104 | snprintf(cp_cmd, sizeof(cp_cmd), "cp -R '%s'/* '%s'", backup_path, path); 105 | if (_system(cp_cmd) != 0) { 106 | printf("Failed to restore contents from %s to %s\n", backup_path, path); 107 | return -1; 108 | } 109 | 110 | NSFileManager *fm = [NSFileManager defaultManager]; 111 | if (![fm removeItemAtPath:[NSString stringWithUTF8String:backup_path] error:nil]) { 112 | printf("Failed to remove backup directory\n"); 113 | return -1; 114 | } 115 | } 116 | 117 | return 0; 118 | } 119 | 120 | int make_running_simulator_runtime_readwrite(void) { 121 | 122 | pid_t sim_launchd_pid = find_pid_of_running_sim_launchd(); 123 | if (sim_launchd_pid == -1) { 124 | printf("Failed to find running sim launchd\n"); 125 | return -1; 126 | } 127 | 128 | char sim_runtime_path[PATH_MAX]; 129 | proc_pidpath(sim_launchd_pid, sim_runtime_path, sizeof(sim_runtime_path)); 130 | NSString *simRuntimePathStr = [NSString stringWithUTF8String:sim_runtime_path]; 131 | NSString *simruntimeRoot = [[simRuntimePathStr stringByDeletingLastPathComponent] stringByDeletingLastPathComponent]; 132 | 133 | NSString *usrLibPath = [simruntimeRoot stringByAppendingPathComponent:@"usr/lib"]; 134 | NSString *dyldSimPath = [usrLibPath stringByAppendingPathComponent:@"dyld_sim"]; 135 | if (![[NSFileManager defaultManager] fileExistsAtPath:dyldSimPath]) { 136 | printf("Failed to find dyld_sim at %s\n", dyldSimPath.UTF8String); 137 | return -1; 138 | } 139 | 140 | if (create_overlay_on_path(usrLibPath.UTF8String, YES) != 0) { 141 | printf("Failed to create overlay on %s\n", usrLibPath.UTF8String); 142 | return -1; 143 | } 144 | 145 | return 0; 146 | } 147 | 148 | #else 149 | 150 | int create_overlay_on_path(const char *path, bool copy_contents) { 151 | printf("Not implemented on non-simulator platform\n"); 152 | return -1; 153 | } 154 | 155 | #endif 156 | -------------------------------------------------------------------------------- /src/objsee-cli/trace_server.h: -------------------------------------------------------------------------------- 1 | // 2 | // trace_server.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/1/24. 6 | // 7 | 8 | #ifndef TRACE_SERVER_H 9 | #define TRACE_SERVER_H 10 | 11 | /** 12 | * Run the trace server on specified port 13 | * 14 | * @param config The configuration to use for the server 15 | * @param traced_pid The pid of the process to trace 16 | * @return 0 on success, 1 on error 17 | */ 18 | int run_trace_server(tracer_config_t *config, pid_t traced_pid); 19 | 20 | #endif // TRACE_SERVER_H 21 | -------------------------------------------------------------------------------- /src/objsee-cli/tui/tui_trace_server.h: -------------------------------------------------------------------------------- 1 | // 2 | // tui_trace_server.h 3 | // libobjsee 4 | // 5 | // Created by Ethan Arbuckle on 12/23/24. 6 | // 7 | 8 | #ifndef tui_trace_server_h 9 | #define tui_trace_server_h 10 | 11 | /** 12 | * Run the curses-based tui trace server 13 | * 14 | * @param config The configuration to use for the server 15 | * @return 0 on success, 1 on error 16 | */ 17 | int run_tui_trace_server(tracer_config_t *config); 18 | 19 | #endif /* tui_trace_server_h */ 20 | -------------------------------------------------------------------------------- /testapp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // testapp 4 | // 5 | // Created by Ethan Arbuckle on 2/8/25. 6 | // 7 | 8 | #import 9 | 10 | @interface AppDelegate : UIResponder 11 | 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /testapp/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // testapp 4 | // 5 | // Created by Ethan Arbuckle on 2/8/25. 6 | // 7 | 8 | #import "AppDelegate.h" 9 | 10 | @interface AppDelegate () 11 | 12 | @end 13 | 14 | @implementation AppDelegate 15 | 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 18 | // Override point for customization after application launch. 19 | 20 | [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 21 | NSLog(@"Response: %@", response); 22 | }] resume]; 23 | 24 | 25 | [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 26 | NSLog(@"Response: %@", response); 27 | }] resume]; 28 | 29 | 30 | [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 31 | NSLog(@"Response: %@", response); 32 | }] resume]; 33 | 34 | return YES; 35 | } 36 | 37 | 38 | #pragma mark - UISceneSession lifecycle 39 | 40 | 41 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { 42 | // Called when a new scene session is being created. 43 | // Use this method to select a configuration to create the new scene with. 44 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; 45 | } 46 | 47 | 48 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { 49 | // Called when the user discards a scene session. 50 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 51 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 52 | } 53 | 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /testapp/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /testapp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "idiom" : "universal", 16 | "platform" : "ios", 17 | "size" : "1024x1024" 18 | }, 19 | { 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "tinted" 24 | } 25 | ], 26 | "idiom" : "universal", 27 | "platform" : "ios", 28 | "size" : "1024x1024" 29 | } 30 | ], 31 | "info" : { 32 | "author" : "xcode", 33 | "version" : 1 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /testapp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testapp/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /testapp/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /testapp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSAllowsArbitraryLoads 8 | 9 | 10 | UIApplicationSceneManifest 11 | 12 | UIApplicationSupportsMultipleScenes 13 | 14 | UISceneConfigurations 15 | 16 | UIWindowSceneSessionRoleApplication 17 | 18 | 19 | UISceneConfigurationName 20 | Default Configuration 21 | UISceneDelegateClassName 22 | SceneDelegate 23 | UISceneStoryboardFile 24 | Main 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /testapp/SceneDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.h 3 | // testapp 4 | // 5 | // Created by Ethan Arbuckle on 2/8/25. 6 | // 7 | 8 | #import 9 | 10 | @interface SceneDelegate : UIResponder 11 | 12 | @property (strong, nonatomic) UIWindow * window; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /testapp/SceneDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.m 3 | // testapp 4 | // 5 | // Created by Ethan Arbuckle on 2/8/25. 6 | // 7 | 8 | #import "SceneDelegate.h" 9 | 10 | @interface SceneDelegate () 11 | 12 | @end 13 | 14 | @implementation SceneDelegate 15 | 16 | 17 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { 18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 21 | } 22 | 23 | 24 | - (void)sceneDidDisconnect:(UIScene *)scene { 25 | // Called as the scene is being released by the system. 26 | // This occurs shortly after the scene enters the background, or when its session is discarded. 27 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 28 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 29 | } 30 | 31 | 32 | - (void)sceneDidBecomeActive:(UIScene *)scene { 33 | // Called when the scene has moved from an inactive state to an active state. 34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 35 | } 36 | 37 | 38 | - (void)sceneWillResignActive:(UIScene *)scene { 39 | // Called when the scene will move from an active state to an inactive state. 40 | // This may occur due to temporary interruptions (ex. an incoming phone call). 41 | } 42 | 43 | 44 | - (void)sceneWillEnterForeground:(UIScene *)scene { 45 | // Called as the scene transitions from the background to the foreground. 46 | // Use this method to undo the changes made on entering the background. 47 | } 48 | 49 | 50 | - (void)sceneDidEnterBackground:(UIScene *)scene { 51 | // Called as the scene transitions from the foreground to the background. 52 | // Use this method to save data, release shared resources, and store enough scene-specific state information 53 | // to restore the scene back to its current state. 54 | } 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /testapp/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // testapp 4 | // 5 | // Created by Ethan Arbuckle on 2/8/25. 6 | // 7 | 8 | #import 9 | 10 | @interface ViewController : UIViewController 11 | 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /testapp/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // testapp 4 | // 5 | // Created by Ethan Arbuckle on 2/8/25. 6 | // 7 | 8 | #import "ViewController.h" 9 | 10 | @interface ViewController () 11 | 12 | @end 13 | 14 | @implementation ViewController 15 | 16 | - (void)viewDidLoad { 17 | [super viewDidLoad]; 18 | // Do any additional setup after loading the view. 19 | } 20 | 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /testapp/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // testapp 4 | // 5 | // Created by Ethan Arbuckle on 2/8/25. 6 | // 7 | 8 | #import 9 | #import "AppDelegate.h" 10 | 11 | #import 12 | 13 | #include 14 | 15 | static tracer_config_t config; 16 | 17 | void objsee_main(const char *encoded_config_string) { 18 | os_log(OS_LOG_DEFAULT, "Loading libobjsee tracer with encoded config"); 19 | 20 | config = (tracer_config_t) { 21 | .transport = TRACER_TRANSPORT_SOCKET, 22 | .format = (tracer_format_options_t) { 23 | .include_colors = false, 24 | .include_formatted_trace = true, 25 | .include_event_json = false, 26 | .output_as_json = false, 27 | .include_thread_id = false, 28 | .include_indents = true, 29 | .indent_char = " ", 30 | .include_indent_separators = true, 31 | .indent_separator_char = "|", 32 | .variable_separator_spacing = false, 33 | .static_separator_spacing = 2, 34 | .include_newline_in_formatted_trace = false, 35 | .args = TRACER_ARG_FORMAT_DESCRIPTIVE, 36 | }, 37 | }; 38 | 39 | tracer_error_t *error = NULL; 40 | tracer_t *tracer = tracer_create_with_config(config, &error); 41 | if (tracer == NULL) { 42 | if (error != NULL) { 43 | os_log(OS_LOG_DEFAULT, "Failed to create tracer: %s", error->message); 44 | free_error(error); 45 | } 46 | return; 47 | } 48 | 49 | tracer_include_class(tracer, "*"); 50 | 51 | tracer_result_t ret = -1; 52 | for (int attempt = 0; attempt < 3; attempt++) { 53 | if ((ret = tracer_start(tracer)) == TRACER_SUCCESS) { 54 | os_log(OS_LOG_DEFAULT, "Tracer started"); 55 | break; 56 | } 57 | else { 58 | os_log(OS_LOG_DEFAULT, "Failed to start tracer: %d (attempt %d)", ret, attempt); 59 | sleep(1); 60 | } 61 | } 62 | 63 | if (ret != TRACER_SUCCESS) { 64 | tracer_cleanup(tracer); 65 | } 66 | } 67 | 68 | 69 | int main(int argc, char * argv[]) { 70 | 71 | objsee_main(NULL); 72 | 73 | NSString * appDelegateClassName; 74 | @autoreleasepool { 75 | // Setup code that might create autoreleased objects goes here. 76 | appDelegateClassName = NSStringFromClass([AppDelegate class]); 77 | } 78 | return UIApplicationMain(argc, argv, nil, appDelegateClassName); 79 | } 80 | --------------------------------------------------------------------------------