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); } }
/** * mono_profiler_coverage_get: * @prof: The profiler handle, installed with mono_profiler_install * @method: the method to gather information from. * @func: A routine that will be called back with the results * * If the MONO_PROFILER_INS_COVERAGE flag was active during JIT compilation * it is posisble to obtain coverage information about a give method. * * The function @func will be invoked repeatedly with instances of the * MonoProfileCoverageEntry structure. */ void mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func) { MonoError error; MonoProfileCoverageInfo* info = NULL; int i, offset; guint32 code_size; const unsigned char *start, *end, *cil_code; MonoMethodHeader *header; MonoProfileCoverageEntry entry; MonoDebugMethodInfo *debug_minfo; mono_profiler_coverage_lock (); if (coverage_hash) info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method); mono_profiler_coverage_unlock (); if (!info) return; header = mono_method_get_header_checked (method, &error); mono_error_assert_ok (&error); start = mono_method_header_get_code (header, &code_size, NULL); debug_minfo = mono_debug_lookup_method (method); end = start + code_size; for (i = 0; i < info->entries; ++i) { cil_code = info->data [i].cil_code; if (cil_code && cil_code >= start && cil_code < end) { char *fname = NULL; offset = cil_code - start; entry.iloffset = offset; entry.method = method; entry.counter = info->data [i].count; entry.line = entry.col = 1; entry.filename = NULL; if (debug_minfo) { MonoDebugSourceLocation *location; location = mono_debug_symfile_lookup_location (debug_minfo, offset); if (location) { entry.line = location->row; entry.col = location->column; entry.filename = fname = g_strdup (location->source_file); mono_debug_free_source_location (location); } } func (prof, &entry); g_free (fname); } } mono_metadata_free_mh (header); }
/** * mono_debug_print_stack_frame: * \param native_offset Native offset within the \p method's machine code. * Conventient wrapper around \c mono_debug_lookup_source_location which can be * used if you only want to use the location to print a stack frame. */ gchar * mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain) { MonoDebugSourceLocation *location; gchar *fname, *ptr, *res; int offset; fname = mono_method_full_name (method, TRUE); for (ptr = fname; *ptr; ptr++) { if (*ptr == ':') *ptr = '.'; } location = mono_debug_lookup_source_location (method, native_offset, domain); if (!location) { if (mono_debug_initialized) { mono_debugger_lock (); offset = il_offset_from_address (method, domain, native_offset); mono_debugger_unlock (); } else { offset = -1; } if (offset < 0 && get_seq_point) offset = get_seq_point (domain, method, native_offset); if (offset < 0) res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset); else { char *mvid = mono_guid_to_string_minimal ((uint8_t*)m_class_get_image (method->klass)->heap_guid.data); char *aotid = mono_runtime_get_aotid (); if (aotid) res = g_strdup_printf ("at %s [0x%05x] in <%s#%s>:0" , fname, offset, mvid, aotid); else res = g_strdup_printf ("at %s [0x%05x] in <%s>:0" , fname, offset, mvid); g_free (aotid); g_free (mvid); } g_free (fname); return res; } res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset, location->source_file, location->row); g_free (fname); mono_debug_free_source_location (location); return res; }
/** * mono_debug_print_stack_frame: * @native_offset: Native offset within the @method's machine code. * * Conventient wrapper around mono_debug_lookup_source_location() which can be * used if you only want to use the location to print a stack frame. */ gchar * mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain) { MonoDebugSourceLocation *location; gchar *fname, *ptr, *res; int offset; fname = mono_method_full_name (method, TRUE); for (ptr = fname; *ptr; ptr++) { if (*ptr == ':') *ptr = '.'; } location = mono_debug_lookup_source_location (method, native_offset, domain); if (!location) { if (mono_debug_initialized) { mono_debugger_lock (); offset = il_offset_from_address (method, domain, native_offset); mono_debugger_unlock (); } else { offset = -1; } if (offset < 0) res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset); else res = g_strdup_printf ("at %s <IL 0x%05x, 0x%05x>", fname, offset, native_offset); g_free (fname); return res; } res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset, location->source_file, location->row); g_free (fname); mono_debug_free_source_location (location); return res; }
/* * mono_debug_add_vg_method: * * Register symbol information for the method with valgrind */ static void mono_debug_add_vg_method (MonoMethod *method, MonoDebugMethodJitInfo *jit) { #ifdef VALGRIND_ADD_LINE_INFO MonoMethodHeader *header; MonoDebugMethodInfo *minfo; int i; char *filename = NULL; guint32 address, line_number; const char *full_name; guint32 *addresses; guint32 *lines; if (!RUNNING_ON_VALGRIND) return; header = mono_method_get_header (method); full_name = mono_method_full_name (method, TRUE); addresses = g_new0 (guint32, header->code_size + 1); lines = g_new0 (guint32, header->code_size + 1); /* * Very simple code to convert the addr->offset mappings that mono has * into [addr-addr] ->line number mappings. */ minfo = mono_debug_lookup_method (method); if (minfo) { /* Create offset->line number mapping */ for (i = 0; i < header->code_size; ++i) { MonoDebugSourceLocation *location; location = mono_debug_symfile_lookup_location (minfo, i); if (!location) continue; lines [i] = location.row; if (!filename) filename = location.source_file; mono_debug_free_source_location (location); } } /* Create address->offset mapping */ for (i = 0; i < jit->num_line_numbers; ++i) { MonoDebugLineNumberEntry *lne = jit->line_numbers [i]; g_assert (lne->offset <= header->code_size); if ((addresses [lne->offset] == 0) || (lne->address < addresses [lne->offset])) addresses [lne->offset] = lne->address; } /* Fill out missing addresses */ address = 0; for (i = 0; i < header->code_size; ++i) { if (addresses [i] == 0) addresses [i] = address; else address = addresses [i]; } address = 0; line_number = 0; i = 0; while (i < header->code_size) { if (lines [i] == line_number) i ++; else { if (line_number > 0) { //g_assert (addresses [i] - 1 >= address); if (addresses [i] - 1 >= address) { VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + addresses [i] - 1, filename, line_number); //printf ("[%d-%d] -> %d.\n", address, addresses [i] - 1, line_number); } } address = addresses [i]; line_number = lines [i]; } } if (line_number > 0) { VALGRIND_ADD_LINE_INFO (jit->code_start + address, jit->code_start + jit->code_size - 1, filename, line_number); //printf ("[%d-%d] -> %d.\n", address, jit->code_size - 1, line_number); } VALGRIND_ADD_SYMBOL (jit->code_start, jit->code_size, full_name); g_free (addresses); g_free (lines); mono_metadata_free_mh (header); #endif /* VALGRIND_ADD_LINE_INFO */ }
static inline gchar *build_hint_from_stack (MonoDomain *domain, void **stack, gint stack_entries) { gchar *hint; MonoMethod *method, *selectedMethod; MonoAssembly *assembly; MonoImage *image; MonoDebugSourceLocation *location; MonoStackBacktraceInfo *info; gboolean use_full_trace; char *methodName; gint i, native_offset, firstAvailable; selectedMethod = NULL; firstAvailable = -1; use_full_trace = FALSE; native_offset = -1; for (i = 0; i < stack_entries; i++) { info = (MonoStackBacktraceInfo*) stack [i]; method = info ? info->method : NULL; if (!method || method->wrapper_type != MONO_WRAPPER_NONE) continue; if (firstAvailable == -1) firstAvailable = i; image = method->klass->image; assembly = image->assembly; if ((assembly && assembly->in_gac) || ignore_frame (method)) continue; selectedMethod = method; native_offset = info->native_offset; break; } if (!selectedMethod) { /* All the frames were from assemblies installed in GAC. Find first frame that is * not in the ignore list */ for (i = 0; i < stack_entries; i++) { info = (MonoStackBacktraceInfo*) stack [i]; method = info ? info->method : NULL; if (!method || ignore_frame (method)) continue; selectedMethod = method; native_offset = info->native_offset; break; } if (!selectedMethod) use_full_trace = TRUE; } hint = NULL; if (use_full_trace) { GString *trace = g_string_new ("Full trace:\n"); for (i = firstAvailable; i < stack_entries; i++) { info = (MonoStackBacktraceInfo*) stack [i]; method = info ? info->method : NULL; if (!method || method->wrapper_type != MONO_WRAPPER_NONE) continue; location = mono_debug_lookup_source_location (method, info->native_offset, domain); methodName = mono_method_full_name (method, TRUE); if (location) { append_report (&trace, LOCATION_INDENT "%s in %s:%u\n", methodName, location->source_file, location->row); mono_debug_free_source_location (location); } else append_report (&trace, LOCATION_INDENT "%s\n", methodName); g_free (methodName); } if (trace) { if (trace->len) hint = g_string_free (trace, FALSE); else g_string_free (trace, TRUE); } } else { location = mono_debug_lookup_source_location (selectedMethod, native_offset, domain); methodName = mono_method_full_name (selectedMethod, TRUE); if (location) { hint = g_strdup_printf (LOCATION_INDENT "%s in %s:%u\n", methodName, location->source_file, location->row); mono_debug_free_source_location (location); } else hint = g_strdup_printf (LOCATION_INDENT "%s\n", methodName); g_free (methodName); } return hint; }