void stack_trace (MonoMethod *method, void *args[], ArmRegs *regs) { LOGD ("stack_trace be call!"); MonoContext ctx; ctx.eip = regs->pc; ctx.esp = regs->sp; ctx.ebp = regs->r11; memcpy (ctx.regs, regs, 4 * 16); MemWriter writer; /*因为当前被跟踪的函数还没被调用(当前在specific_trampo中), 所以这里手动写入当前函数的跟踪结构*/ char const *m = get_method_image_name (method); m = m ? m : "NO_IMAGE_NAME"; char const *n = mono_method_full_name (method, 1); if (n) { writer.sprintf ("[%s]%s[%08X]\n", m, n, mono_method_get_token (method)); g_free (n); } else { writer.sprintf ("[%s]%s[%08X]\n", m, "NO_METHOD_NAME", mono_method_get_token (method)); } mono_walk_stack (mono_domain_get (), 0, &ctx, walk_stack, &writer); xmono::StackTraceRsp rsp; rsp.set_err (true); rsp.set_stack (std::string ((char*)writer.getBuffPtr (), writer.getBuffSize ())); std::string out; rsp.SerializeToString (&out); ecmd_send (XMONO_ID_STACK_TRACE_RSP, (uint8_t const*)out.c_str (), out.size ()); }
static int walk_stack (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *jit_info, void *user_data) { MemWriter *writer = (MemWriter*)user_data; MonoMethod *method =mono_jit_info_get_method (jit_info); if (!method) { writer->sprintf("%s", "jit_info no method!"); return 0; } char const *m = get_method_image_name (method); m = m ? m : "NO_IMAGE_NAME"; char const *n = mono_method_full_name (method, 1); if (n) { writer->sprintf ("[%s] %s [%08X]\n", m, n, mono_method_get_token (method)); g_free (n); } else { writer->sprintf ("[%s] %s [%08X]\n", m, "NO_METHOD_NAME", mono_method_get_token (method)); } return 0; /*一直walk, 直到栈帧尽头*/ }
static void foreach_method (gpointer data, gpointer user_data) { ForeachData *udata = (ForeachData*)user_data; MonoMethod *method = (MonoMethod*)data; char *name; if (!mono_method_get_token (method) || mono_class_get_image (mono_method_get_class (method)) != udata->image) return; name = mono_method_full_name (method, TRUE); fprintf (udata->outfile, "%s\n", name); g_free (name); }
/*监控需要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; }
MonoDebugMethodInfo * mono_debug_symfile_lookup_method (MonoDebugHandle *handle, MonoMethod *method) { MonoSymbolFileMethodEntry *first_ie, *ie; MonoDebugMethodInfo *minfo; MonoSymbolFile *symfile = handle->symfile; if (!symfile->method_hash) return NULL; if (handle->image != mono_class_get_image (mono_method_get_class (method))) return NULL; mono_debugger_lock (); minfo = g_hash_table_lookup (symfile->method_hash, method); if (minfo) { mono_debugger_unlock (); return minfo; } first_ie = (MonoSymbolFileMethodEntry *) (symfile->raw_contents + read32(&(symfile->offset_table->_method_table_offset))); ie = bsearch (GUINT_TO_POINTER (mono_method_get_token (method)), first_ie, read32(&(symfile->offset_table->_method_count)), sizeof (MonoSymbolFileMethodEntry), compare_method); if (!ie) { mono_debugger_unlock (); return NULL; } minfo = g_new0 (MonoDebugMethodInfo, 1); minfo->index = (ie - first_ie) + 1; minfo->method = method; minfo->handle = handle; minfo->data_offset = read32 (&(ie->_data_offset)); minfo->lnt_offset = read32 (&(ie->_line_number_table)); g_hash_table_insert (symfile->method_hash, method, minfo); mono_debugger_unlock (); return minfo; }
static void send_trace_log (std::map<MonoMethod*, CallInfo> const &dict) { MemWriter sbuf(0x100000); MemWriter writer(0x100000); std::map<MonoMethod*, CallInfo>::const_iterator p; for (p = dict.begin (); p != dict.end (); p++) { MonoMethod *method = p->first; CallInfo call_info = p->second; char const *m = get_method_image_name (method); char *n = mono_method_full_name (method, 0); char str[256]; sbuf.sprintf ("[%s] %s [%08X]|%d|%d\n", m, n, mono_method_get_token (method), call_info.times, call_info.order); g_free (n); } if (!compress_data (sbuf.getBuffPtr (), sbuf.getBuffSize (), &writer)) { LOGD ("compress_data err!"); return; } /*Fixme : 这里写在使用protocolbuf之前, 因此非常不河蟹的出现了不使用pb的封包*/ ecmd_send (XMONO_ID_TRACE_REPORT, writer.getBuffPtr (), writer.getBuffSize ()); return; }
static void output_method (MonoMethod *method, gpointer dummy, MonoProfiler *prof) { MonoMethodHeader *header; char *classname; char *tmpsig; char *tmpname; FILE *outfile; MonoClass *klass; MonoImage *image; outfile = prof->outfile; header = mono_method_get_header (method); tmpsig = mono_signature_get_desc (mono_method_signature (method), TRUE); tmpsig = g_markup_escape_text (tmpsig, strlen (tmpsig)); klass = mono_method_get_class (method); classname = mono_type_get_name (mono_class_get_type (klass)); image = mono_class_get_image (klass); tmpname = mono_method_get_name (method); tmpname = g_markup_escape_text (tmpname, strlen (tmpname)); fprintf (outfile, "\t<method assembly=\"%s\" class=\"%s\" name=\"%s (%s)\" token=\"%d\">\n", mono_image_get_name (image), classname, tmpname, tmpsig, mono_method_get_token (method)); g_free (tmpsig); g_free (tmpname); fprintf (outfile, "\t\t"); count = 0; prev_offset = 0; mono_profiler_coverage_get (prof, method, output_entry); fprintf (outfile, "\n"); fprintf (outfile, "\t</method>\n"); }
static void disasm_method (Package *pkg) { xmono::DisasmMethodReq req; xmono::DisasmMethodRsp rsp; std::string str((char*)pkg->body, pkg->all_len - sizeof (Package)); //Fixme : 修复头部all_len是总长的问题 if (!req.ParseFromString (str)) { LOGD ("xmono::DisasmMethodReq ParseFromString err!"); return; } std::string err(""); MonoMethod *method = get_method_with_token (req.image_name ().c_str (), req.method_token ()); if (!method) err += helper_last_err (); MonoImage *image = mono_image_loaded (req.image_name ().c_str ()); if (!image) err += " image : " + req.image_name () + " can not be find!"; if (image && method) { MemWriter writer(4096); char const *mname = mono_method_full_name (method, 1); if (mname) { writer.sprintf ("//[%s]%s[%08X]\n", get_method_image_name (method), mname, mono_method_get_token (method)); g_free (mname); } MonoMethodHeader *header = mono_method_get_header (method); disassemble_cil (image, header, &writer); /*Fixme : disassemble_cil需要在失败时返回更多信息*/ rsp.set_err (true); LOGD ("writer : %s", writer.getBuffPtr ()); std::string s((char*)writer.getBuffPtr (), writer.getBuffSize ()); rsp.set_disasm_code (s); //这部分只是测试用的 uint32_t asm_size = 0; uint8_t const *p = mono_method_header_get_code (header, &asm_size, 0); std::string asm_code ((char const*)p, asm_size); rsp.set_asm_code (asm_code); } else { rsp.set_err (false); rsp.set_err_str (err); } std::string out; rsp.SerializeToString (&out); ecmd_send (XMONO_ID_DISASM_METHOD_RSP, (uint8_t const*)out.c_str (), out.size ()); return; }