Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
indulgeIn committed Aug 2, 2020
1 parent 0fa80b0 commit 0aa86cb
Show file tree
Hide file tree
Showing 75 changed files with 4,899 additions and 1 deletion.
29 changes: 29 additions & 0 deletions MessageMock.podspec
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
109 changes: 109 additions & 0 deletions MessageMock/Core/mm_argument_callback.cpp
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
15 changes: 15 additions & 0 deletions MessageMock/Core/mm_argument_callback.h
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 */
115 changes: 115 additions & 0 deletions MessageMock/Core/mm_argument_change.cpp
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
15 changes: 15 additions & 0 deletions MessageMock/Core/mm_argument_change.h
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 */
61 changes: 61 additions & 0 deletions MessageMock/Core/mm_argument_stack.cpp
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;
}
25 changes: 25 additions & 0 deletions MessageMock/Core/mm_argument_stack.h
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 */
17 changes: 17 additions & 0 deletions MessageMock/Core/mm_define.h
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 */
Loading

0 comments on commit 0aa86cb

Please sign in to comment.