??Matrix 中的 memory hook 也是基于 xhook 的實(shí)現(xiàn)的,可以記錄 malloc、calloc、free、mmap 等函數(shù)的調(diào)用。
1.初始化
??初始化主要做了二件事,一是 hook 函數(shù)的調(diào)用,二是開啟了一個(gè) while(true) 線程將記錄的數(shù)據(jù)由一組容器轉(zhuǎn)移變換到另一組容器中。
JNIEXPORT void JNICALL
Java_com_tencent_matrix_hook_memory_MemoryHook_installHooksNative(JNIEnv* env, jobject thiz,
jobjectArray hook_so_patterns,
jobjectArray ignore_so_patterns,
jboolean enable_debug) {
// 開啟線程
memory_hook_init();
xhook_block_refresh();
{
jsize size = env->GetArrayLength(hook_so_patterns);
for (int i = 0; i < size; ++i) {
auto jregex = (jstring) env->GetObjectArrayElement(hook_so_patterns, i);
const char* regex = env->GetStringUTFChars(jregex, nullptr);
// hook 函數(shù)調(diào)用
hook(regex);
env->ReleaseStringUTFChars(jregex, regex);
}
}
...
xhook_grouped_ignore(HOOK_REQUEST_GROUPID_MEMORY, ".*/libandroid_runtime\\.so$", nullptr);
xhook_unblock_refresh();
}
- hook 函數(shù)調(diào)用
static void hook(const char *regex) { // regex 是 hook 哪個(gè) so 的名字,
for (auto f : HOOK_MALL_FUNCTIONS) {
int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr);
LOGD(TAG, "hook fn, regex: %s, sym: %s, ret: %d", regex, f.name, ret);
}
LOGD(TAG, "mmap enabled ? %d", enable_mmap_hook);
// 是否 hook mmap
if (enable_mmap_hook) {
for (auto f: HOOK_MMAP_FUNCTIONS) {
xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr);
}
}
}
// 其中需要 hook 的函數(shù)有如下
// 與開辟、釋放空間相關(guān)的
const HookFunction HOOK_MALL_FUNCTIONS[] = {
{"malloc", (void *) h_malloc, NULL},
{"calloc", (void *) h_calloc, NULL},
{"realloc", (void *) h_realloc, NULL},
{"free", (void *) h_free, NULL},
{"memalign", (void *) HANDLER_FUNC_NAME(memalign), NULL},
{"posix_memalign", (void *) HANDLER_FUNC_NAME(posix_memalign), NULL},
// CXX functions
#ifndef __LP64__
...
#else
{"_Znwm", (void*) HANDLER_FUNC_NAME(_Znwm), NULL},
{"_ZnwmSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZnwmSt11align_val_t), NULL},
{"_ZnwmSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnwmSt11align_val_tRKSt9nothrow_t), NULL},
{"_ZnwmRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnwmRKSt9nothrow_t), NULL},
{"_Znam", (void*) HANDLER_FUNC_NAME(_Znam), NULL},
{"_ZnamSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZnamSt11align_val_t), NULL},
{"_ZnamSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnamSt11align_val_tRKSt9nothrow_t), NULL},
{"_ZnamRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZnamRKSt9nothrow_t), NULL},
{"_ZdlPvm", (void*) HANDLER_FUNC_NAME(_ZdlPvm), NULL},
{"_ZdlPvmSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdlPvmSt11align_val_t), NULL},
{"_ZdaPvm", (void*) HANDLER_FUNC_NAME(_ZdaPvm), NULL},
{"_ZdaPvmSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdaPvmSt11align_val_t), NULL},
#endif
{"_ZdlPv", (void*) HANDLER_FUNC_NAME(_ZdlPv), NULL},
{"_ZdlPvSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdlPvSt11align_val_t), NULL},
{"_ZdlPvSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdlPvSt11align_val_tRKSt9nothrow_t), NULL},
{"_ZdlPvRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdlPvRKSt9nothrow_t), NULL},
{"_ZdaPv", (void*) HANDLER_FUNC_NAME(_ZdaPv), NULL},
{"_ZdaPvSt11align_val_t", (void*) HANDLER_FUNC_NAME(_ZdaPvSt11align_val_t), NULL},
{"_ZdaPvSt11align_val_tRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdaPvSt11align_val_tRKSt9nothrow_t), NULL},
{"_ZdaPvRKSt9nothrow_t", (void*) HANDLER_FUNC_NAME(_ZdaPvRKSt9nothrow_t), NULL},
{"strdup", (void*) HANDLER_FUNC_NAME(strdup), (void **) ORIGINAL_FUNC_NAME(strdup)},
{"strndup", (void*) HANDLER_FUNC_NAME(strndup), (void **) ORIGINAL_FUNC_NAME(strndup)},
};
// 與 mmap 相關(guān)的
static const HookFunction HOOK_MMAP_FUNCTIONS[] = {
{"mmap", (void *) h_mmap, NULL},
{"munmap", (void *) h_munmap, NULL},
{"mremap", (void *) h_mremap, NULL},
#if __ANDROID_API__ >= __ANDROID_API_L__
{"mmap64", (void *) h_mmap64, NULL},
#endif
};
// 轉(zhuǎn)換前
int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, regex, f.name, f.handler_ptr, f.origin_ptr);
// 實(shí)際 hook
int ret = xhook_grouped_register(HOOK_REQUEST_GROUPID_MEMORY, ".*library-not-exists\\.so$",malloc, (void *) h_malloc, NULL);
而實(shí)際調(diào)用的 h_malloc 函數(shù)也需要進(jìn)行一點(diǎn)點(diǎn)轉(zhuǎn)化才可以得到
DEFINE_HOOK_FUN(void *, malloc, size_t __byte_count) {
CALL_ORIGIN_FUNC_RET(void*, p, malloc, __byte_count);
LOGI(TAG, "+ malloc %p", p);
DO_HOOK_ACQUIRE(p, __byte_count);
return p;
}
// 將上面的代碼進(jìn)行宏替換后得到
fn_malloc_t orig_malloc;
void * h_malloc(size_t __byte_count){
if(!orig_malloc){
void *handle = dlopen("libc.so", 0x00001);
if(handle){
orig_malloc = (fn_malloc_t)dlsym(handle,malloc)
}
}
void* p = orig_malloc(__byte_count);
LOGI(TAG, "+ malloc %p", p);
void * __caller_addr = __builtin_return_address(0);
on_alloc_memory(caller, p, __byte_count);
return p;
}
當(dāng)調(diào)用相關(guān) hook 函數(shù)后,先通過(guò) dlopen 打開 libc.so ,在拿到 libc.so 里面的 malloc 原函數(shù),先調(diào)用原函數(shù),拿到 hook 函數(shù)的返回地址之后再通過(guò) on_alloc_memory 函數(shù)來(lái)記錄 原malloc 函數(shù)的返回地址,開辟的大小及 hook 函數(shù)的返回地址。
- 開啟一個(gè)線程,
memory_hook_init
// memory_meta_container 構(gòu)造函數(shù) 舒適化了 ptr_meta_containers、stack_meta_containers 這二個(gè)容器
static memory_meta_container m_memory_meta_container;
// memory_meta_container() {
// size_t cap = ptr_meta_capacity();// 1
// ptr_meta_containers.reserve(cap);// 申請(qǐng)n個(gè)元素的內(nèi)存空間
// for (int i = 0; i < cap; ++i) {
// ptr_meta_containers.emplace_back(new ptr_meta_container_wrapper_t);
// }
//
// cap = stack_meta_capacity();// 1
// stack_meta_containers.reserve(cap);
// for (int i = 0; i < cap; ++i) {
// stack_meta_containers.emplace_back(new stack_container_wrapper_t);
// }
// }
// BufferManagement 構(gòu)造函數(shù)中將容器 containers_ 初始化并添加了 1<<8 個(gè) BufferQueueContainer() 對(duì)象
static BufferManagement m_memory_messages_containers_(&m_memory_meta_container);
// BufferManagement::BufferManagement(memory_meta_container *memory_meta_container) {
//
// containers_.reserve(MAX_PTR_SLOT);// 1<<8
// for (int i = 0; i < MAX_PTR_SLOT; ++i) {
// auto container = new BufferQueueContainer();
// containers_.emplace_back(container);
// }
// memory_meta_container_ = memory_meta_container;
// }
// 調(diào)用的是這里
void memory_hook_init() {
m_memory_messages_containers_.start_process();
}
void BufferManagement::start_process() {
if (processing_) return;
processing_ = true;
pthread_create(&thread_, nullptr,
reinterpret_cast<void *(*)(void *)>(&BufferManagement::process_routine),
this);
pthread_detach(thread_);
}
// 數(shù)據(jù)由 BufferManagement::containers_ 容器轉(zhuǎn)移變化到了 BufferManagement::memory_meta_container_ 里面
// 而 BufferManagement::memory_meta_container_ 是個(gè)靜態(tài)對(duì)象
[[noreturn]] void BufferManagement::process_routine(BufferManagement *this_) {
size_t last_total_message_counter = 0;
size_t total_message_counter = 0;
while (true) {
if (!this_->queue_swapped_) this_->queue_swapped_ = new BufferQueue(SIZE_AUGMENT); // 192
size_t busy_queue = 0;
for (auto container : this_->containers_) { // 遍歷 1<<8 個(gè)對(duì)象
HOOK_LOG_ERROR("Process routine ... ");
BufferQueue *swapped = nullptr;
{
std::lock_guard<std::mutex> lock(container->mutex_);
if (container->queue_ && !container->queue_->empty()) { // 判斷是否為空,不為空就將其 queue_ 賦值給 queue_swapped_ 并將原來(lái)的值清空
HOOK_LOG_ERROR("Swap queue ... ");
// 將數(shù)據(jù)賦值給 swapped,并且把 container 里面的數(shù)據(jù)置空
swapped = container->queue_;
container->queue_ = this_->queue_swapped_;
}
}
if (swapped && swapped->size() >= 5) {
busy_queue++;
}
if (swapped) {
HOOK_LOG_ERROR("Swapped ... ");
swapped->process( // 依次取出 messages_ 和 allocation_message_t 記錄的信息
// 依次拿到記錄在 container 內(nèi)的 messages_ 和 allocations_ 容器 里面的內(nèi)容
[&](message_t *message, allocation_message_t *allocation_message) {
total_message_counter++;
if (message->type == message_type_allocation || message->type == message_type_reallocation ||
message->type == message_type_mmap) {
if (UNLIKELY(allocation_message == nullptr)) {
CRITICAL_CHECK(allocation_message);
return;
}
uint64_t stack_hash = 0;
// 開辟大小不為 0 且 有 native stack 就 hash
// 之前 wechat backtrace 工具記錄的
if (allocation_message->size != 0 &&
allocation_message->backtrace.frame_size != 0) {
stack_hash = hash_frames(
allocation_message->backtrace.frames,
allocation_message->backtrace.frame_size);
}
// 一個(gè) static obj
// 有一樣的 native stack 的話就放在一個(gè)類似與鏈表的地方,沒(méi)有的話就新建一個(gè) 像 HashMap<String,LinkArray>?
// 返回插入的 ptr 和 stack 對(duì)象給這邊add數(shù)據(jù),對(duì)飲之前的 messages_ 和 allocation_message_t 對(duì)象
// memory_meta_container_ 是一個(gè)靜態(tài)變量
this_->memory_meta_container_->insert(
reinterpret_cast<const void *>(allocation_message->ptr),
stack_hash,
allocation_message,
[&](ptr_meta_t *ptr_meta, stack_meta_t *stack_meta) { // 回調(diào)填充數(shù)據(jù)
ptr_meta->ptr = reinterpret_cast<void *>(allocation_message->ptr);
ptr_meta->size = allocation_message->size;
ptr_meta->attr.is_mmap =
message->type == message_type_mmap;
if (UNLIKELY(!stack_meta)) {
ptr_meta->caller = allocation_message->caller;
return;
}
stack_meta->size += allocation_message->size;
if (stack_meta->backtrace.frame_size == 0 &&
allocation_message->backtrace.frame_size != 0) {
stack_meta->backtrace = allocation_message->backtrace;
stack_meta->caller = allocation_message->caller;
}
});
} else if (message->type == message_type_deletion ||
message->type == message_type_munmap) {
this_->memory_meta_container_->erase(
reinterpret_cast<const void *>(message->ptr));
}
});
// messages_ 及 allocations_ 容器置空
swapped->reset();
this_->queue_swapped_ = swapped;
}
}
}
}
總結(jié):將數(shù)據(jù)由 BufferManagement::containers_ 容器轉(zhuǎn)移到了 BufferManagement::memory_meta_container_ 里面。
2.hook 記錄相關(guān)信息
??分析 malloc 及 free 這二個(gè)函數(shù) hook 之后記錄的信息。
- 1.malloc hook
??在初始化中提到malloc的 hook 函數(shù)是h_malloc,而該函數(shù)通過(guò)dlopen打開libc.so,在拿到libc.so里面的malloc原函數(shù),先調(diào)用原函數(shù),拿到 hook 函數(shù)的返回地址之后再通過(guò)on_alloc_memory函數(shù)來(lái)記錄原malloc函數(shù)的返回地址,開辟的大小及 hook 函數(shù)的返回地址。
void on_alloc_memory(void *caller, void *ptr, size_t byte_count) {
on_acquire_memory(caller, ptr, byte_count, message_type_allocation);
}
// m_memory_messages_containers_ 是上面的 BufferManagement 對(duì)象
static inline void on_acquire_memory(
void *caller,
void *ptr,
size_t byte_count,
message_type type) {
// BufferManagement::containers_ 里面有 1<<8 個(gè) BufferQueueContainer 對(duì)象
// hash ptr 后從 1<<8 拿到其 BufferQueueContainer
BufferQueueContainer *container = m_memory_messages_containers_.containers_[memory_ptr_hash(
(uintptr_t) ptr)];
{
memory_backtrace_t backtrace{0};
// 應(yīng)該是 wechat 的 native stack tools 代碼,先不用管
if (LIKELY(byte_count > 0 && is_stacktrace_enabled && should_do_unwind(byte_count))) {
size_t frame_size = 0;
do_unwind(backtrace.frames, MEMHOOK_BACKTRACE_MAX_FRAMES,
frame_size);
backtrace.frame_size = frame_size;
}
// 原子操作上鎖 并初始化 BufferQueueContainer(即 container) 中的 queue_ 對(duì)象
container->lock();
// inline void lock() {
// if (UNLIKELY(!mutex_.try_lock())) {
// g_locker_collision_counter.fetch_add(1, std::memory_order_relaxed);
// mutex_.lock();
// }
//
// if (UNLIKELY(!queue_)) {
// queue_ = new BufferQueue(SIZE_AUGMENT);//192
// }
// }
auto message = container->queue_->enqueue_allocation_message(type);
// inline allocation_message_t *enqueue_allocation_message(message_type type) {
// // 初始化的操作 resize=194 T 是 message_t 類型
// // void *buffer = realloc(queue_, sizeof(T) * resize);
// // queue_ = static_cast<T *>(buffer);
// 從容量為194的容器取出 index 從0開始累加的 message_t
// 總結(jié) 就是給 index = idx 的 message_t 賦值
// message_t *msg_idx = &messages_->queue_[messages_->idx_++];// idx 從0開始加
// msg_idx->type = type; // message_type_allocation
// msg_idx->index = allocations_->idx_; // 也是從0開始加
// // 總結(jié) 返回 index = idx 的 allocation_message_t ,準(zhǔn)備給這個(gè)對(duì)象賦值
// allocation_message_t *buffer = &allocations_->queue_[allocations_->idx_++];
// *buffer = {};
// return buffer;
// }
if (UNLIKELY(!message)) {
BufferQueueContainer::g_message_overflow_counter.fetch_add(1,
std::memory_order_relaxed);
CHECK_MESSAGE_OVERFLOW(!message);
} else {
// 給上面返回的 allocation_message_t 對(duì)象賦值,有 malloc 函數(shù)的返回地址,開辟的字節(jié)數(shù),malloc 所在函數(shù)的返回地址及 wechat 的一個(gè)棧幀
message->ptr = reinterpret_cast<uintptr_t>(ptr);
message->size = byte_count;
message->caller = reinterpret_cast<uintptr_t>(caller);
if (backtrace.frame_size) {
message->backtrace = backtrace;
}
}
container->unlock();
}
}
- malloc hook 總結(jié):
- 取 BufferManagement::containers_ 容器(size=1<<8) BufferQueueContainer,index 是 ptr 的一種 hash
- 初始化 BufferQueueContainer 中的 queue_ = new BufferQueue(SIZE_AUGMENT);//192
BufferQueue 中有二個(gè)對(duì)象 messages_ 和 allocations_,二個(gè)都是容器(size=194)
- 初始化 BufferQueueContainer 中的 queue_ = new BufferQueue(SIZE_AUGMENT);//192
-
- &messages_->queue_[messages_->idx_++];取出 queue_ 中 index = idx(該值是自加1的)并賦值
- 3.1 主要是賦hook的類型( message_type_allocation malloc的類型)和 allocations_ 容器的索引
-
- allocation_message_t *buffer = &allocations_->queue_[allocations_->idx_++];取出 queue_ 中 index = idx(該值是自加1的)并賦值
- 4.1 主要是malloc 函數(shù)的返回地址,開辟的字節(jié)數(shù),malloc 所在函數(shù)的返回地址及 wechat 的一個(gè)棧幀
- 2.free hook
free hook 的代碼宏替換后會(huì)調(diào)到on_free_memory函數(shù),ptr 是釋放空間的指針
void on_free_memory(void *ptr) {
on_release_memory(ptr, false);
}
static inline void on_release_memory(void *ptr, bool is_munmap) {
BufferQueueContainer *container = m_memory_messages_containers_.containers_[memory_ptr_hash(
(uintptr_t) ptr)];
container->lock();
bool ret = container->queue_->enqueue_deletion_message(reinterpret_cast<uintptr_t>(ptr),
is_munmap);
// inline bool enqueue_deletion_message(uintptr_t ptr, bool is_munmap) {
//
// // Fast path. 如果ptr相也就是malloc開辟的空間被free了,messages_->idx_>0
// if (messages_->idx_ > 0) {
// message_t *msg_idx = &messages_->queue_[messages_->idx_ - 1];
// if (((!is_munmap && msg_idx->type == message_type_allocation)
// || (is_munmap && msg_idx->type == message_type_mmap))
// && allocations_->queue_[msg_idx->index].ptr == ptr) {
// msg_idx->type = message_type_nil;
// messages_->idx_--;
// allocations_->idx_--;
// return true;
// }
// }
//
// if (UNLIKELY(!messages_->check_realloc())) {
// return false;
// }
//
// message_t *msg_idx = &messages_->queue_[messages_->idx_++];
// msg_idx->type = is_munmap ? message_type_munmap : message_type_deletion;
// msg_idx->ptr = ptr;
//
// return true;
// }
container->unlock();
if (UNLIKELY(!ret)) {
BufferQueueContainer::g_message_overflow_counter.fetch_add(1, std::memory_order_relaxed);
CHECK_MESSAGE_OVERFLOW(!ret);
}
}
- free hook 總結(jié)
- 取 BufferManagement::containers_ 容器(size=1<<8) BufferQueueContainer,index 是 ptr 的一種 hash
- 初始化 BufferQueueContainer 中的 queue_ = new BufferQueue(SIZE_AUGMENT);//192
BufferQueue 中有二個(gè)對(duì)象 messages_ 和 allocations_,二個(gè)都是容器(size=194)
- 初始化 BufferQueueContainer 中的 queue_ = new BufferQueue(SIZE_AUGMENT);//192
-
- &messages_->queue_[messages_->idx_++];取出 queue_ 中 index = idx(該值是自加1的)并賦值
- 3.1 如果((!mmap&&type==malloc)||(mmap&&type=mmap))&&(allocations_->queue_[msg_idx->index].ptr == ptr)的話就刪除之前的 message_t 對(duì)象里面的內(nèi)容,否則執(zhí)行3.2
- 3.2 主要是賦hook的類型( message_type_deletion delete類型)和 ptr free 的指針
一句話就是 free 的 ptr 是之前記錄的就刪除記錄的內(nèi)容,不是之前的記錄該 free 的 ptr 及 type
3.dump 信息
在 hook 之后,相關(guān)的信息就被記錄到 BufferManagement::containers_中了,而在初始化中又會(huì)將記錄的信息轉(zhuǎn)移到BufferManagement::memory_meta_container_這個(gè)容器中,所以想得到記錄的相關(guān)信息只需要遍歷這個(gè)容器即可。
void dump(bool enable_mmap, const char *log_path, const char *json_path) {
dump_impl(log_file, json_file, enable_mmap);
DUMP_RECORD("/sdcard/Android/data/com.tencent.mm/memory-record.dump");
}
static inline void dump_impl(FILE *log_file, FILE *json_file, bool mmap) {
std::map<void *, caller_meta_t> heap_caller_metas;
std::map<void *, caller_meta_t> mmap_caller_metas;
std::map<uint64_t, stack_meta_t> heap_stack_metas;
std::map<uint64_t, stack_meta_t> mmap_stack_metas;
// 返回值是 放了多少個(gè)數(shù)據(jù)
size_t ptr_meta_size = collect_metas(heap_caller_metas,
mmap_caller_metas,
heap_stack_metas,
mmap_stack_metas);
// 下面就是將上面容器中的數(shù)據(jù)組裝起來(lái)
cJSON *json_obj = cJSON_CreateObject();
cJSON *so_native_size_arr = cJSON_AddArrayToObject(json_obj, "SoNativeSize");
// native heap allocation
dump_callers(log_file, so_native_size_arr, heap_caller_metas);
cJSON *native_heap_arr = cJSON_AddArrayToObject(json_obj, "NativeHeap");
dump_stacks(log_file, native_heap_arr, heap_stack_metas);
if (mmap) {
...
}
char *printed = cJSON_PrintUnformatted(json_obj);
flogger0(json_file, "%s", printed);
LOGD(TAG, "===> %s", printed);
cJSON_free(printed);
cJSON_Delete(json_obj);
}
static inline size_t collect_metas(std::map<void *, caller_meta_t> &heap_caller_metas,
std::map<void *, caller_meta_t> &mmap_caller_metas,
std::map<uint64_t, stack_meta_t> &heap_stack_metas,
std::map<uint64_t, stack_meta_t> &mmap_stack_metas) {
LOGD(TAG, "collect_metas");
size_t ptr_meta_size = 0;
// 由初始化的 memory_hook_init(); 函數(shù),將記錄的 hook 數(shù)據(jù)從 BufferManagement::containers_ 容器轉(zhuǎn)移變化到了 BufferManagement::memory_meta_container_ 里面
// 也就是 m_memory_meta_container 這個(gè)里面有記錄的 hook 的數(shù)據(jù)
// 取出了 ptr, &ptr_meta, stack_meta 數(shù)據(jù)
m_memory_meta_container.for_each(
[&](const void *ptr, ptr_meta_t *meta, stack_meta_t *stack_meta) { // 依次取出了 ptr, &ptr_meta, stack_meta 數(shù)據(jù)
// 區(qū)分 native heap 和 mmap 的 caller 和 stack
auto &dest_caller_metes =
meta->attr.is_mmap ? mmap_caller_metas : heap_caller_metas;
auto &dest_stack_metas = meta->attr.is_mmap ? mmap_stack_metas : heap_stack_metas;
void *caller;
if (stack_meta) {
caller = reinterpret_cast<void *>(stack_meta->caller);
} else {
caller = reinterpret_cast<void *>(meta->caller);
}
// 向參數(shù)里面的 map 放數(shù)據(jù)
if (caller) {
caller_meta_t &caller_meta = dest_caller_metes[caller];
caller_meta.pointers.insert(ptr);
caller_meta.total_size += meta->size;
}
// 向參數(shù)里面的 map 放數(shù)據(jù)
if (stack_meta) {
auto &dest_stack_meta = dest_stack_metas[(uint64_t) stack_meta];
dest_stack_meta.backtrace = stack_meta->backtrace;
// 沒(méi)錯(cuò), 這里的確使用 ptr_meta 的 size, 因?yàn)槭窃诒闅v ptr_meta, 因此原來(lái) stack_meta 的 size 僅起引用計(jì)數(shù)作用
dest_stack_meta.size += meta->size;
dest_stack_meta.caller = stack_meta->caller;
}
ptr_meta_size++;
});
LOGD(TAG, "collect_metas done");
return ptr_meta_size; // map 中的個(gè)數(shù)
}
void for_each(std::function<void(const void *, ptr_meta_t *, stack_meta_t *)> __callback) {
// 這個(gè)就是初始化中開啟線程轉(zhuǎn)移變化數(shù)據(jù)的目的容器
for (const auto cw : ptr_meta_containers) {
std::lock_guard<std::mutex> container_lock(cw->mutex);
cw->container.enumerate([&](const void *ptr, ptr_meta_t &ptr_meta) {
if (ptr_meta.stack_hash) {
TARGET_STACK_CONTAINER_LOCKED(stack_meta_container, ptr_meta.stack_hash);
// 宏替換后的
// stack_container_wrapper_t *stack_meta_container = stack_meta_containers.data()[stack_meta_hash(ptr_meta.stack_hash)];
// std::lock_guard<std::mutex> stack_lock(stack_meta_container->mutex)
stack_meta_t *stack_meta = nullptr;
if (LIKELY(stack_meta_container->container.exist(ptr_meta.stack_hash))) {
if (ptr_meta.attr.is_stack_idx) {
stack_meta = &stack_meta_container->container.get(ptr_meta.stack_idx);
} else {
stack_meta = reinterpret_cast<stack_meta_t *>(ptr_meta.ext_stack_ptr);
}
}
__callback(ptr, &ptr_meta, stack_meta); // 回調(diào)到上面那個(gè)函數(shù)
} else {
__callback(ptr, &ptr_meta, nullptr);
}
});
}
}
至此分析結(jié)束。