-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
75 changed files
with
4,899 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
Pod::Spec.new do |s| | ||
|
||
s.name = "MessageMock" | ||
|
||
s.version = "1.0" | ||
|
||
s.summary = "Objective-C 方法模拟工具" | ||
|
||
s.description = <<-DESC | ||
Objective-C 方法模拟工具 | ||
DESC | ||
|
||
s.homepage = "https://github.com/indulgeIn" | ||
|
||
s.license = "MIT" | ||
|
||
s.author = { "indulgeIn" => "[email protected]" } | ||
|
||
s.platform = :ios, "9.0" | ||
|
||
s.source = { :git => "https://github.com/indulgeIn/MessageMock.git", :tag => "#{s.version}" } | ||
|
||
s.requires_arc = true | ||
|
||
s.source_files = "MessageMock/**/*.{h,m,mm,c,cpp,hpp}" | ||
|
||
s.libraries = 'c++.1' | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// | ||
// mm_argument_callback.cpp | ||
// MessageMock | ||
// | ||
// Created by 波儿菜 on 2020/7/10. | ||
// | ||
|
||
#import "mm_argument_callback.h" | ||
|
||
#ifdef __aarch64__ | ||
|
||
#import <stdlib.h> | ||
#import "mm_define.h" | ||
#import "mm_method_matcher.h" | ||
#import "mm_runtime.h" | ||
|
||
using namespace mm_method_matcher; | ||
|
||
void MMArgumentCallbackIfNeeded(uintptr_t self, uintptr_t _cmd) { | ||
#define XS_SIZE 6 | ||
#define DS_SIZE 8 | ||
uintptr_t xs[XS_SIZE], ds[DS_SIZE]; | ||
__asm volatile | ||
("mov %0, x2\n" | ||
"mov %1, x3\n" | ||
"mov %2, x4\n" | ||
"mov %3, x5\n" | ||
"mov %4, x6\n" | ||
"mov %5, x7\n" | ||
: "=r"(xs[0]), "=r"(xs[1]), "=r"(xs[2]), "=r"(xs[3]), "=r"(xs[4]), "=r"(xs[5])); | ||
__asm volatile | ||
("fmov %0, d0\n" | ||
"fmov %1, d1\n" | ||
"fmov %2, d2\n" | ||
"fmov %3, d3\n" | ||
"fmov %4, d4\n" | ||
"fmov %5, d5\n" | ||
"fmov %6, d6\n" | ||
"fmov %7, d7\n" | ||
: "=r"(ds[0]), "=r"(ds[1]), "=r"(ds[2]), "=r"(ds[3]), "=r"(ds[4]), "=r"(ds[5]), "=r"(ds[6]), "=r"(ds[7])); | ||
|
||
ArgumentCallbackMap *callback_map = NULL; | ||
{ | ||
MethodMatcherLock lock; | ||
MethodMatcher *matcher = UnsafeGetMethodMatcher(self, _cmd); | ||
if (MM_UNLIKELY(matcher)) { | ||
callback_map = matcher->argument_callback_map; | ||
|
||
++matcher->using_count; | ||
} | ||
} | ||
if (MM_LIKELY(!callback_map || callback_map->size() <= 0)) { | ||
return; | ||
} | ||
|
||
Method method = MMGetMethod((id)self, (SEL)_cmd); | ||
unsigned int arg_number = method_getNumberOfArguments(method); | ||
|
||
ArgumentCallbackError error = kArgumentCallbackErrorNone; | ||
unsigned int x_idx = 0, d_idx = 0; | ||
for (unsigned int i = 2; i < arg_number; ++i) { | ||
ArgumentCallback callback = callback_map->find(i)->second; | ||
if (!callback) { | ||
continue; | ||
} | ||
|
||
if (error == kArgumentCallbackErrorUnsupported) { | ||
callback(0, error); | ||
continue; | ||
} | ||
|
||
char *type = method_copyArgumentType(method, i); | ||
if (MM_UNLIKELY(!type)) { // 该路径理论上不会走 | ||
callback(0, kArgumentCallbackErrorNoIndex); | ||
continue; | ||
} | ||
|
||
uintptr_t arg = 0; | ||
if (MM_UNLIKELY(MMPtrLengthArgumentTypes().count(*type) > 0)) { | ||
if (*type == 'f' || *type == 'd') { | ||
if (MM_UNLIKELY(d_idx >= DS_SIZE)) { | ||
error = kArgumentCallbackErrorOverD7; | ||
} else { | ||
arg = ds[d_idx++]; | ||
} | ||
} else { | ||
if (MM_UNLIKELY(x_idx >= XS_SIZE)) { | ||
error = kArgumentCallbackErrorOverX7; | ||
} else { | ||
arg = xs[x_idx++]; | ||
} | ||
} | ||
} else { | ||
error = kArgumentCallbackErrorUnsupported; | ||
} | ||
|
||
callback(arg, error); | ||
free(type); | ||
} | ||
|
||
#undef XS_SIZE | ||
#undef DS_SIZE | ||
} | ||
|
||
#else | ||
|
||
void MMArgumentCallbackIfNeeded(uintptr_t self, uintptr_t _cmd) {} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// mm_argument_callback.h | ||
// MessageMock | ||
// | ||
// Created by 波儿菜 on 2020/7/10. | ||
// | ||
|
||
#ifndef mm_argument_callback_h | ||
#define mm_argument_callback_h | ||
|
||
#include <stdio.h> | ||
|
||
void MMArgumentCallbackIfNeeded(uintptr_t self, uintptr_t _cmd); | ||
|
||
#endif /* mm_argument_callback_h */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// | ||
// mm_argument_change.cpp | ||
// MessageMock | ||
// | ||
// Created by 波儿菜 on 2020/7/13. | ||
// | ||
|
||
#import "mm_argument_change.h" | ||
|
||
#ifdef __aarch64__ | ||
|
||
#import <unordered_map> | ||
#import "mm_define.h" | ||
#import "mm_runtime.h" | ||
#import "mm_method_matcher.h" | ||
|
||
using namespace mm_method_matcher; | ||
|
||
void MMSetArgumentRegisters(uintptr_t self, uintptr_t _cmd) { | ||
uintptr_t arg_label = 0; | ||
|
||
#define XS_SIZE 6 | ||
#define DS_SIZE 8 | ||
//通用/浮点寄存器值暂存数组 | ||
uintptr_t xs[XS_SIZE] = {0}, ds[DS_SIZE] = {0}, mask = 1; | ||
{ | ||
ArgumentList *arguments = NULL; | ||
{ | ||
MethodMatcherLock lock; | ||
MethodMatcher *matcher = UnsafeGetMethodMatcher(self, _cmd); | ||
if (MM_UNLIKELY(matcher)) { | ||
arguments = matcher->arguments; | ||
} | ||
} | ||
if (!arguments || arguments->size() <= 0) { | ||
__asm volatile ("b 16f"); | ||
} | ||
|
||
Method method = MMGetMethod((id)self, (SEL)_cmd); | ||
unsigned int arg_number = method_getNumberOfArguments(method); | ||
|
||
std::unordered_map<unsigned int, uintptr_t> x_register_map, d_register_map; | ||
uintptr_t x_idx = 2, d_idx = 0; | ||
for (unsigned int i = 2; i < arg_number; ++i) { | ||
char *type = method_copyArgumentType(method, i); | ||
if (MM_UNLIKELY(!type || MMPtrLengthArgumentTypes().count(*type) == 0)) { | ||
// Unsupported argument type. | ||
__asm volatile ("b 16f"); | ||
} | ||
if (*type == 'f' || *type == 'd') { | ||
d_register_map[i] = d_idx++; | ||
} else { | ||
x_register_map[i] = x_idx++; | ||
} | ||
free(type); | ||
} | ||
|
||
for (Argument arg : *arguments) { | ||
char *type = method_copyArgumentType(method, arg.idx); | ||
if (MM_UNLIKELY(!type)) { | ||
continue; | ||
} | ||
uintptr_t res_arg = arg.value; | ||
if (arg.object) { | ||
res_arg = (uintptr_t)arg.object; | ||
} | ||
if (*type == 'f' || *type == 'd') { | ||
uintptr_t register_idx = d_register_map[arg.idx]; | ||
if (MM_UNLIKELY(register_idx >= DS_SIZE)) { | ||
continue; | ||
} | ||
arg_label |= (mask << (8 + register_idx)); | ||
ds[register_idx] = res_arg; | ||
} else { | ||
uintptr_t register_idx = x_register_map[arg.idx]; | ||
if (MM_UNLIKELY(register_idx - 2 >= XS_SIZE)) { | ||
continue; | ||
} | ||
arg_label |= (mask << register_idx); | ||
xs[register_idx - 2] = res_arg; | ||
} | ||
free(type); | ||
} | ||
} | ||
#undef XS_SIZE | ||
#undef DS_SIZE | ||
|
||
__asm volatile | ||
("mov x2, %0\n" | ||
"mov x3, %1\n" | ||
"mov x4, %2\n" | ||
"mov x5, %3\n" | ||
"mov x6, %4\n" | ||
"mov x7, %5\n" | ||
:: "r"(xs[0]), "r"(xs[1]), "r"(xs[2]), "r"(xs[3]), "r"(xs[4]), "r"(xs[5])); | ||
__asm volatile | ||
("fmov d0, %0\n" | ||
"fmov d1, %1\n" | ||
"fmov d2, %2\n" | ||
"fmov d3, %3\n" | ||
"fmov d4, %4\n" | ||
"fmov d5, %5\n" | ||
"fmov d6, %6\n" | ||
"fmov d7, %7\n" | ||
:: "r"(ds[0]), "r"(ds[1]), "r"(ds[2]), "r"(ds[3]), "r"(ds[4]), "r"(ds[5]), "r"(ds[6]), "r"(ds[7])); | ||
|
||
__asm volatile ("16:"); | ||
__asm volatile ("mov x0, %0" :: "r"(arg_label)); | ||
} | ||
|
||
#else | ||
|
||
void MMSetArgumentRegisters(uintptr_t self, uintptr_t _cmd) {} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// mm_argument_change.h | ||
// MessageMock | ||
// | ||
// Created by 波儿菜 on 2020/7/13. | ||
// | ||
|
||
#ifndef mm_argument_change_h | ||
#define mm_argument_change_h | ||
|
||
#include <stdio.h> | ||
|
||
void MMSetArgumentRegisters(uintptr_t self, uintptr_t _cmd); | ||
|
||
#endif /* mm_argument_change_h */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// | ||
// mm_argument_stack.cpp | ||
// MessageMock | ||
// | ||
// Created by 波儿菜 on 2020/7/10. | ||
// | ||
|
||
#import "mm_argument_stack.h" | ||
#import <pthread.h> | ||
#import <stdlib.h> | ||
#import "mm_define.h" | ||
|
||
typedef struct { | ||
MMArgumentItem *items; | ||
int index; | ||
int mask; | ||
} MMArgumentStack; | ||
|
||
static pthread_key_t argument_stack_thread_key; | ||
|
||
static void ArgumentStackThreadRelease(void *ptr) { | ||
MMArgumentStack *stack = (MMArgumentStack *)ptr; | ||
if (MM_LIKELY(stack)) { | ||
if (MM_LIKELY(stack->items)) { | ||
free(stack->items); | ||
} | ||
free(stack); | ||
} | ||
} | ||
|
||
void MMThreadKeyCreate(void) { | ||
pthread_key_create(&argument_stack_thread_key, &ArgumentStackThreadRelease); | ||
} | ||
|
||
static MMArgumentStack *GetArgumentStack() { | ||
MMArgumentStack *stack = (MMArgumentStack *)pthread_getspecific(argument_stack_thread_key); | ||
if (MM_UNLIKELY(!stack)) { | ||
stack = (MMArgumentStack *)malloc(sizeof(MMArgumentStack)); | ||
stack->mask = 128; | ||
stack->index = -1; | ||
stack->items = (MMArgumentItem *)calloc(stack->mask, sizeof(MMArgumentItem)); | ||
pthread_setspecific(argument_stack_thread_key, stack); | ||
} | ||
return stack; | ||
} | ||
|
||
void MMArgumentStackPush(MMArgumentItem item) { | ||
MMArgumentStack *stack = GetArgumentStack(); | ||
int index = ++stack->index; | ||
if (MM_UNLIKELY(index >= stack->mask)) { | ||
stack->mask += 128; | ||
stack->items = (MMArgumentItem *)realloc(stack->items, stack->mask * sizeof(MMArgumentItem)); | ||
} | ||
stack->items[index] = item; | ||
} | ||
|
||
MMArgumentItem MMArgumentStackPop() { | ||
MMArgumentStack *stack = GetArgumentStack(); | ||
MMArgumentItem item = stack->items[stack->index--]; | ||
return item; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// | ||
// mm_argument_stack.h | ||
// MessageMock | ||
// | ||
// Created by 波儿菜 on 2020/7/10. | ||
// | ||
|
||
#ifndef mm_argument_stack_h | ||
#define mm_argument_stack_h | ||
|
||
#include <stdio.h> | ||
|
||
typedef struct { | ||
uintptr_t target; | ||
uintptr_t selector; | ||
uintptr_t lr; | ||
} MMArgumentItem; | ||
|
||
void MMThreadKeyCreate(void); | ||
|
||
void MMArgumentStackPush(MMArgumentItem item); | ||
|
||
MMArgumentItem MMArgumentStackPop(void); | ||
|
||
#endif /* mm_argument_stack_h */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// | ||
// mm_define.h | ||
// MessageMock | ||
// | ||
// Created by 波儿菜 on 2020/7/10. | ||
// | ||
|
||
#ifndef mm_define_h | ||
#define mm_define_h | ||
|
||
#define MM_LIKELY(x) (__builtin_expect(!!(x), 1)) | ||
#define MM_UNLIKELY(x) (__builtin_expect(!!(x), 0)) | ||
|
||
#define MM_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") | ||
#define MM_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") | ||
|
||
#endif /* mm_define_h */ |
Oops, something went wrong.