static void mop_jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result) { static int n = 0; char* name = mono_method_full_name (method, TRUE); char* start = mono_jit_info_get_code_start (jinfo); int len = mono_jit_info_get_code_size (jinfo); int i; JitRange * jr; jr = mop_get_jit_range (start); for (i = 0; name [i]; ++i) { if (!isalnum (name [i])) name [i] = '_'; } fprintf (assm, ".section vm%d\n", jr->rangenum); fprintf (assm, ".org %p\n", (char*)start - (char*)jr->start); fprintf (assm, "%s%d:\n", name, ++n); for (i = 0; i < len; i ++) { fprintf (assm, ".byte %d; ", start [i]); } fprintf (assm, "\n\n\n"); g_free (name); }
static void method_jit_result (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result) { if (result == MONO_PROFILE_OK) { int i; MonoDebugSourceLocation *sourceLoc; MonoDebugMethodJitInfo *dmji; MonoClass *klass = mono_method_get_class (method); char *signature = mono_signature_get_desc (mono_method_signature (method), TRUE); char *name = g_strdup_printf ("%s(%s)", mono_method_get_name (method), signature); char *classname = g_strdup_printf ("%s%s%s", mono_class_get_namespace (klass), mono_class_get_namespace (klass)[0] != 0 ? "::" : "", mono_class_get_name (klass)); gpointer code_start = mono_jit_info_get_code_start (jinfo); int code_size = mono_jit_info_get_code_size (jinfo); iJIT_Method_Load vtuneMethod; memset(&vtuneMethod, 0, sizeof(vtuneMethod)); vtuneMethod.method_id = iJIT_GetNewMethodID(); vtuneMethod.method_name = name; vtuneMethod.method_load_address = code_start; vtuneMethod.method_size = code_size; vtuneMethod.class_file_name = classname; dmji = mono_debug_find_method (method, mono_domain_get()); if (dmji != NULL) { vtuneMethod.line_number_size = dmji->num_line_numbers; vtuneMethod.line_number_table = (vtuneMethod.line_number_size != 0) ? (LineNumberInfo*)malloc(sizeof(LineNumberInfo) * vtuneMethod.line_number_size) : NULL; for (i = 0; i < dmji->num_line_numbers; ++i) { sourceLoc = mono_debug_lookup_source_location (method, dmji->line_numbers[i].native_offset, mono_domain_get()); if (sourceLoc == NULL) { g_free (vtuneMethod.line_number_table); vtuneMethod.line_number_table = NULL; vtuneMethod.line_number_size = 0; break; } if (i == 0) vtuneMethod.source_file_name = strdup(sourceLoc->source_file); vtuneMethod.line_number_table[i].Offset = dmji->line_numbers[i].native_offset; vtuneMethod.line_number_table[i].LineNumber = sourceLoc->row; mono_debug_free_source_location (sourceLoc); } mono_debug_free_method_jit_info (dmji); } iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &vtuneMethod); if (vtuneMethod.source_file_name != NULL) g_free (vtuneMethod.source_file_name); if (vtuneMethod.line_number_table != NULL) g_free (vtuneMethod.line_number_table); g_free (signature); g_free (name); g_free (classname); } }
void CPipeServer::GetJitInfo() { void *domain=(void *)ReadQword(); void *address=(void *)ReadQword(); void *jitinfo=mono_jit_info_table_find(domain, address); WriteQword((UINT_PTR)jitinfo); if (jitinfo) { WriteQword((UINT_PTR)mono_jit_info_get_method(jitinfo)); WriteQword((UINT_PTR)mono_jit_info_get_code_start(jitinfo)); WriteDword((UINT_PTR)mono_jit_info_get_code_size(jitinfo)); } }
/*监控需要hook的函数*/ static void profile_jit_result (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result) { if (result == MONO_PROFILE_FAILED) return; if (mono_method_get_token (method) == 0) return; /*一般是动态生成的marshall*/ uint32_t iflags; int flag = mono_method_get_flags (method, &iflags); if (iflags != 0) return; /*iflags非0 一般是一些native和特殊的method实现*/ if (mono_jit_info_get_code_size (jinfo) < 4) return; /*代码段太小, 无法hook*/ void *p = mono_jit_info_get_code_start (jinfo); if (p == 0) { LOGD ("function code size is null"); return; } /*测试jit函数是否是mov r12, sp*/ if (*(uint32_t*)p != 0xE1A0C00D) LOGD ("exception func : %s , %p", mono_method_get_name (method), p); /*TODO : 增加可配置的image和函数列表*/ if (strcmp (get_method_image_name (method), "Assembly-CSharp") != 0) return; if (strcmp (mono_method_get_name (method), ".ctor") == 0) return; if (strcmp (mono_method_get_name (method), ".cctor") == 0) return; if (strcmp (mono_method_get_name (method), "set") == 0) return; if (strcmp (mono_method_get_name (method), "get") == 0) return; if (strcmp (mono_method_get_name (method), "Update") == 0) return; if (strcmp (mono_method_get_name (method), "LateUpdate") == 0) return; if (strcmp (mono_method_get_name (method), "OnGUI") == 0) return; /*TODO : 需要一个容器来存储还未编译, 但又想hook的函数*/ bool donthook = false; pthread_mutex_lock (&replace_mutex); if (replace_method_dict.find (method) != replace_method_dict.end ()) donthook = true; pthread_mutex_unlock (&replace_mutex); if (donthook) return; char *hook = specific_hook (p, method, (void*)func_trace); if (hook == 0) { /*将失败的hook也放到一个表里面*/ LOGD ("hook err : %s", mono_method_get_name (method)); return; } pthread_mutex_lock (&hooked_mutex); hooked_method_dict[method] = new HookInfo(jinfo, hook); pthread_mutex_unlock (&hooked_mutex); LOGD ("hook func : %s , %p", mono_method_get_name (method), p); return; }
static void replace_method (Package *pkg) { xmono::ReplaceMethodReq req; xmono::ReplaceMethodRsp rsp; std::string str((char*)pkg->body, pkg->all_len - sizeof (Package)); if (!req.ParseFromString (str)) { LOGD ("xmono::ReplaceMethodReq ParseFromString err!"); return; } std::string err; void *p, *old_p; uint8_t *code; int code_size; MonoMethodHeader *mh; MonoThread *thread; MonoMethod *new_method; MonoDomain *domain; MonoMethod * method = get_method_with_token (req.image_name ().c_str (), req.method_token ()); if (!method) { rsp.set_err (false); rsp.set_msg (helper_last_err ()); goto replace_method_end; } domain = mono_domain_get_by_id (req.domain_id ()); if (!domain) { rsp.set_err (false); rsp.set_msg ("can not get the domain from id"); goto replace_method_end; } mh = mono_method_get_header (method); if (req.ex_size () != mono_method_header_get_num_clauses (mh)) { rsp.set_err (false); rsp.set_msg ("ex size != mono_method_header_clauses size!"); goto replace_method_end; } for (int i = 0; i < req.ex_size (); i++) { xmono::ReplaceMethodReq_ExceptionClause const &e = req.ex (i); void *iter = 0; MonoExceptionClause *clauses = &mh->clauses[i]; MonoExceptionClause *old_e = (MonoExceptionClause*)iter; old_e->try_offset = e.try_offset (); old_e->try_len = e.try_len (); old_e->handler_offset = e.handler_offset (); old_e->handler_len = e.handler_len (); } code = new uint8_t[req.new_code ().size ()]; memcpy (code, req.new_code ().c_str (), req.new_code ().size ()); mh->code = code; mh->code_size = req.new_code ().size (); thread = mono_thread_attach (domain); /*128 是一个估计值, 在未来可能不稳定, 但当前只能如此*/ new_method = (MonoMethod*)calloc (128, 1); /*这个地方用malloc优于用new*/ memcpy (new_method, method, 128); pthread_mutex_lock (&replace_mutex); replace_method_dict[new_method] = true; pthread_mutex_unlock (&replace_mutex); p = mono_compile_method (new_method); memcpy (hooked_method_dict[method]->specific_hook + 4, &p, 4); pthread_mutex_lock (&hooked_mutex); old_p = mono_jit_info_get_code_start (hooked_method_dict[method]->jinfo); pthread_mutex_unlock (&hooked_mutex); mono_thread_detach (thread); LOGD ("compile method, new ptr : %p, old ptr : %p", p, old_p); rsp.set_err (true); rsp.set_msg ("replace_method successful."); replace_method_end: std::string out; rsp.SerializeToString (&out); ecmd_send (XMONO_ID_REPLACE_METHOD_RSP, (uint8_t const*)out.c_str (), out.size ()); return; }