static void foreach_method (const gpointer key, const gpointer val, gpointer user_data) { MonoMethod *method = key; MonoClass *klass = user_data; if (method->klass != klass) return; /* FIXME: ensure it's the correct token */ fprintf (outf, "M:0x%x\n", mono_metadata_token_index (method->token)); }
static void foreach_field (const gpointer key, const gpointer val, gpointer user_data) { MonoClassField *field = key; MonoClass *klass = user_data; int idx; if (field->parent != klass) return; idx = mono_metadata_token_index (mono_class_get_field_token (field)); fprintf (outf, "F:0x%x\n", idx); }
static void foreach_type (const gpointer key, const gpointer val, gpointer user_data) { MonoClass *klass = key; MonoImage *image = user_data; if (klass->image != image) return; if (klass->rank || klass->byval_arg.type == MONO_TYPE_PTR) return; fprintf (outf, "T:0x%x\n", mono_metadata_token_index (klass->type_token)); g_hash_table_foreach (method_table, foreach_method, klass); g_hash_table_foreach (field_table, foreach_field, klass); }
// for parent_type see HasCustomDebugInformation table at // https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PortablePdb-Metadata.md static const char* lookup_custom_debug_information (MonoImage* image, guint32 token, uint8_t parent_type, guint8* guid) { MonoTableInfo *tables = image->tables; MonoTableInfo *table = &tables[MONO_TABLE_CUSTOMDEBUGINFORMATION]; locator_t loc; if (!table->base) return 0; loc.idx = (mono_metadata_token_index (token) << 5) | parent_type; loc.col_idx = MONO_CUSTOMDEBUGINFORMATION_PARENT; loc.t = table; if (!mono_binary_search (&loc, table->base, table->rows, table->row_size, table_locator)) return NULL; // Great we found one of possibly many CustomDebugInformations of this entity they are distinguished by KIND guid // First try on this index found by binary search...(it's most likeley to be only one and binary search found the one we want) if (compare_guid (guid, (guint8*)mono_metadata_guid_heap (image, mono_metadata_decode_row_col (table, loc.result, MONO_CUSTOMDEBUGINFORMATION_KIND)))) return mono_metadata_blob_heap (image, mono_metadata_decode_row_col (table, loc.result, MONO_CUSTOMDEBUGINFORMATION_VALUE)); // Move forward from binary found index, until parent token differs for (int i = loc.result + 1; i < table->rows; i++) { if (mono_metadata_decode_row_col (table, i, MONO_CUSTOMDEBUGINFORMATION_PARENT) != loc.idx) break; if (compare_guid (guid, (guint8*)mono_metadata_guid_heap (image, mono_metadata_decode_row_col (table, i, MONO_CUSTOMDEBUGINFORMATION_KIND)))) return mono_metadata_blob_heap (image, mono_metadata_decode_row_col (table, i, MONO_CUSTOMDEBUGINFORMATION_VALUE)); } // Move backward from binary found index, until parent token differs for (int i = loc.result - 1; i >= 0; i--) { if (mono_metadata_decode_row_col (table, i, MONO_CUSTOMDEBUGINFORMATION_PARENT) != loc.idx) break; if (compare_guid (guid, (guint8*)mono_metadata_guid_heap (image, mono_metadata_decode_row_col (table, i, MONO_CUSTOMDEBUGINFORMATION_KIND)))) return mono_metadata_blob_heap (image, mono_metadata_decode_row_col (table, i, MONO_CUSTOMDEBUGINFORMATION_VALUE)); } return NULL; }
static const unsigned char* dis_one (GString *str, MonoDisHelper *dh, MonoMethod *method, const unsigned char *ip, const unsigned char *end) { MonoMethodHeader *header = mono_method_get_header (method); const MonoOpcode *opcode; guint32 label, token; gint32 sval; int i; char *tmp; const unsigned char* il_code = mono_method_header_get_code (header, NULL, NULL); label = ip - il_code; if (dh->indenter) { tmp = dh->indenter (dh, method, label); g_string_append (str, tmp); g_free (tmp); } if (dh->label_format) g_string_append_printf (str, dh->label_format, label); i = mono_opcode_value (&ip, end); ip++; opcode = &mono_opcodes [i]; g_string_append_printf (str, "%-10s", mono_opcode_name (i)); switch (opcode->argument) { case MonoInlineNone: break; case MonoInlineType: case MonoInlineField: case MonoInlineMethod: case MonoInlineTok: case MonoInlineSig: token = read32 (ip); if (dh->tokener) { tmp = dh->tokener (dh, method, token); g_string_append (str, tmp); g_free (tmp); } else { g_string_append_printf (str, "0x%08x", token); } ip += 4; break; case MonoInlineString: { const char *blob; char *s; size_t len2; char *blob2 = NULL; if (!image_is_dynamic (method->klass->image) && !method_is_dynamic (method)) { token = read32 (ip); blob = mono_metadata_user_string (method->klass->image, mono_metadata_token_index (token)); len2 = mono_metadata_decode_blob_size (blob, &blob); len2 >>= 1; #ifdef NO_UNALIGNED_ACCESS /* The blob might not be 2 byte aligned */ blob2 = g_malloc ((len2 * 2) + 1); memcpy (blob2, blob, len2 * 2); #else blob2 = (char*)blob; #endif #if G_BYTE_ORDER != G_LITTLE_ENDIAN { guint16 *buf = g_new (guint16, len2 + 1); int i; for (i = 0; i < len2; ++i) buf [i] = GUINT16_FROM_LE (((guint16*)blob2) [i]); s = g_utf16_to_utf8 (buf, len2, NULL, NULL, NULL); g_free (buf); } #else s = g_utf16_to_utf8 ((gunichar2*)blob2, len2, NULL, NULL, NULL); #endif g_string_append_printf (str, "\"%s\"", s); g_free (s); if (blob != blob2) g_free (blob2); } ip += 4; break; } case MonoInlineVar: g_string_append_printf (str, "%d", read16 (ip)); ip += 2; break; case MonoShortInlineVar: g_string_append_printf (str, "%d", (*ip)); ip ++; break; case MonoInlineBrTarget: sval = read32 (ip); ip += 4; if (dh->label_target) g_string_append_printf (str, dh->label_target, ip + sval - il_code); else g_string_append_printf (str, "%d", sval); break; case MonoShortInlineBrTarget: sval = *(const signed char*)ip; ip ++; if (dh->label_target) g_string_append_printf (str, dh->label_target, ip + sval - il_code); else g_string_append_printf (str, "%d", sval); break; case MonoInlineSwitch: { const unsigned char *end; sval = read32 (ip); ip += 4; end = ip + sval * 4; g_string_append_c (str, '('); for (i = 0; i < sval; ++i) { if (i > 0) g_string_append (str, ", "); label = read32 (ip); if (dh->label_target) g_string_append_printf (str, dh->label_target, end + label - il_code); else g_string_append_printf (str, "%d", label); ip += 4; } g_string_append_c (str, ')'); break; } case MonoInlineR: { double r; readr8 (ip, &r); g_string_append_printf (str, "%g", r); ip += 8; break; } case MonoShortInlineR: { float r; readr4 (ip, &r); g_string_append_printf (str, "%g", r); ip += 4; break; } case MonoInlineI: g_string_append_printf (str, "%d", (gint32)read32 (ip)); ip += 4; break; case MonoShortInlineI: g_string_append_printf (str, "%d", *(const signed char*)ip); ip ++; break; case MonoInlineI8: ip += 8; break; default: g_assert_not_reached (); }
MonoDebugLocalsInfo* mono_ppdb_lookup_locals (MonoDebugMethodInfo *minfo) { MonoPPDBFile *ppdb = minfo->handle->ppdb; MonoImage *image = ppdb->image; MonoTableInfo *tables = image->tables; MonoMethod *method = minfo->method; guint32 cols [MONO_LOCALSCOPE_SIZE]; guint32 locals_cols [MONO_LOCALVARIABLE_SIZE]; int i, lindex, sindex, method_idx, start_scope_idx, scope_idx, locals_idx, locals_end_idx, nscopes; MonoDebugLocalsInfo *res; MonoMethodSignature *sig; if (!method->token) return NULL; sig = mono_method_signature (method); if (!sig) return NULL; method_idx = mono_metadata_token_index (method->token); start_scope_idx = mono_metadata_localscope_from_methoddef (image, method_idx); if (!start_scope_idx) return NULL; /* Compute number of locals and scopes */ scope_idx = start_scope_idx; mono_metadata_decode_row (&tables [MONO_TABLE_LOCALSCOPE], scope_idx-1, cols, MONO_LOCALSCOPE_SIZE); locals_idx = cols [MONO_LOCALSCOPE_VARIABLELIST]; // https://github.com/dotnet/roslyn/blob/2ae8d5fed96ab3f1164031f9b4ac827f53289159/docs/specs/PortablePdb-Metadata.md#LocalScopeTable // // The variableList attribute in the pdb metadata table is a contiguous array that starts at a // given offset (locals_idx) above and // // """ // continues to the smaller of: // // the last row of the LocalVariable table // the next run of LocalVariables, found by inspecting the VariableList of the next row in this LocalScope table. // """ // this endpoint becomes locals_end_idx below // March to the last scope that is in this method while (scope_idx <= tables [MONO_TABLE_LOCALSCOPE].rows) { mono_metadata_decode_row (&tables [MONO_TABLE_LOCALSCOPE], scope_idx-1, cols, MONO_LOCALSCOPE_SIZE); if (cols [MONO_LOCALSCOPE_METHOD] != method_idx) break; scope_idx ++; } // The number of scopes is the difference in the indices // for the first and last scopes nscopes = scope_idx - start_scope_idx; // Ends with "the last row of the LocalVariable table" // this happens if the above loop marched one past the end // of the rows if (scope_idx > tables [MONO_TABLE_LOCALSCOPE].rows) { locals_end_idx = tables [MONO_TABLE_LOCALVARIABLE].rows + 1; } else { // Ends with "the next run of LocalVariables, // found by inspecting the VariableList of the next row in this LocalScope table." locals_end_idx = cols [MONO_LOCALSCOPE_VARIABLELIST]; } res = g_new0 (MonoDebugLocalsInfo, 1); res->num_blocks = nscopes; res->code_blocks = g_new0 (MonoDebugCodeBlock, res->num_blocks); res->num_locals = locals_end_idx - locals_idx; res->locals = g_new0 (MonoDebugLocalVar, res->num_locals); lindex = 0; for (sindex = 0; sindex < nscopes; ++sindex) { scope_idx = start_scope_idx + sindex; mono_metadata_decode_row (&tables [MONO_TABLE_LOCALSCOPE], scope_idx-1, cols, MONO_LOCALSCOPE_SIZE); locals_idx = cols [MONO_LOCALSCOPE_VARIABLELIST]; if (scope_idx == tables [MONO_TABLE_LOCALSCOPE].rows) { locals_end_idx = tables [MONO_TABLE_LOCALVARIABLE].rows + 1; } else { locals_end_idx = mono_metadata_decode_row_col (&tables [MONO_TABLE_LOCALSCOPE], scope_idx-1 + 1, MONO_LOCALSCOPE_VARIABLELIST); } res->code_blocks [sindex].start_offset = cols [MONO_LOCALSCOPE_STARTOFFSET]; res->code_blocks [sindex].end_offset = cols [MONO_LOCALSCOPE_STARTOFFSET] + cols [MONO_LOCALSCOPE_LENGTH]; //printf ("Scope: %s %d %d %d-%d\n", mono_method_full_name (method, 1), cols [MONO_LOCALSCOPE_STARTOFFSET], cols [MONO_LOCALSCOPE_LENGTH], locals_idx, locals_end_idx); for (i = locals_idx; i < locals_end_idx; ++i) { mono_metadata_decode_row (&tables [MONO_TABLE_LOCALVARIABLE], i - 1, locals_cols, MONO_LOCALVARIABLE_SIZE); res->locals [lindex].name = g_strdup (mono_metadata_string_heap (image, locals_cols [MONO_LOCALVARIABLE_NAME])); res->locals [lindex].index = locals_cols [MONO_LOCALVARIABLE_INDEX]; res->locals [lindex].block = &res->code_blocks [sindex]; lindex ++; //printf ("\t %s %d\n", mono_metadata_string_heap (image, locals_cols [MONO_LOCALVARIABLE_NAME]), locals_cols [MONO_LOCALVARIABLE_INDEX]); } } return res; }
void mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points) { MonoPPDBFile *ppdb = minfo->handle->ppdb; MonoImage *image = ppdb->image; MonoMethod *method = minfo->method; MonoTableInfo *tables = image->tables; guint32 cols [MONO_METHODBODY_SIZE]; const char *ptr; const char *end; MonoDebugSourceInfo *docinfo; int i, method_idx, size, docidx, iloffset, delta_il, delta_lines, delta_cols, start_line, start_col, adv_line, adv_col; gboolean first = TRUE, first_non_hidden = TRUE; GArray *sps; MonoSymSeqPoint sp; GPtrArray *sfiles = NULL; GPtrArray *sindexes = NULL; if (source_file) *source_file = NULL; if (source_file_list) *source_file_list = NULL; if (source_files) *source_files = NULL; if (seq_points) *seq_points = NULL; if (n_seq_points) *n_seq_points = 0; if (source_file_list) *source_file_list = sfiles = g_ptr_array_new (); if (source_files) sindexes = g_ptr_array_new (); if (!method->token) return; method_idx = mono_metadata_token_index (method->token); mono_metadata_decode_row (&tables [MONO_TABLE_METHODBODY], method_idx-1, cols, MONO_METHODBODY_SIZE); docidx = cols [MONO_METHODBODY_DOCUMENT]; if (!cols [MONO_METHODBODY_SEQ_POINTS]) return; ptr = mono_metadata_blob_heap (image, cols [MONO_METHODBODY_SEQ_POINTS]); size = mono_metadata_decode_blob_size (ptr, &ptr); end = ptr + size; sps = g_array_new (FALSE, TRUE, sizeof (MonoSymSeqPoint)); /* Header */ /* LocalSignature */ mono_metadata_decode_value (ptr, &ptr); if (docidx == 0) docidx = mono_metadata_decode_value (ptr, &ptr); docinfo = get_docinfo (ppdb, image, docidx); if (sfiles) g_ptr_array_add (sfiles, docinfo); if (source_file) *source_file = g_strdup (docinfo->source_file); iloffset = 0; start_line = 0; start_col = 0; while (ptr < end) { delta_il = mono_metadata_decode_value (ptr, &ptr); if (!first && delta_il == 0) { /* subsequent-document-record */ docidx = mono_metadata_decode_value (ptr, &ptr); docinfo = get_docinfo (ppdb, image, docidx); if (sfiles) g_ptr_array_add (sfiles, docinfo); continue; } iloffset += delta_il; first = FALSE; delta_lines = mono_metadata_decode_value (ptr, &ptr); if (delta_lines == 0) delta_cols = mono_metadata_decode_value (ptr, &ptr); else delta_cols = mono_metadata_decode_signed_value (ptr, &ptr); if (delta_lines == 0 && delta_cols == 0) { /* Hidden sequence point */ continue; } if (first_non_hidden) { start_line = mono_metadata_decode_value (ptr, &ptr); start_col = mono_metadata_decode_value (ptr, &ptr); } else { adv_line = mono_metadata_decode_signed_value (ptr, &ptr); adv_col = mono_metadata_decode_signed_value (ptr, &ptr); start_line += adv_line; start_col += adv_col; } first_non_hidden = FALSE; memset (&sp, 0, sizeof (sp)); sp.il_offset = iloffset; sp.line = start_line; sp.column = start_col; sp.end_line = start_line + delta_lines; sp.end_column = start_col + delta_cols; g_array_append_val (sps, sp); if (source_files) g_ptr_array_add (sindexes, GUINT_TO_POINTER (sfiles->len - 1)); } if (n_seq_points) { *n_seq_points = sps->len; g_assert (seq_points); *seq_points = g_new (MonoSymSeqPoint, sps->len); memcpy (*seq_points, sps->data, sps->len * sizeof (MonoSymSeqPoint)); } if (source_files) { *source_files = g_new (int, sps->len); for (i = 0; i < sps->len; ++i) (*source_files)[i] = GPOINTER_TO_INT (g_ptr_array_index (sindexes, i)); g_ptr_array_free (sindexes, TRUE); } g_array_free (sps, TRUE); }
/** * mono_ppdb_lookup_location: * \param minfo A \c MonoDebugMethodInfo which can be retrieved by mono_debug_lookup_method(). * \param offset IL offset within the corresponding method's CIL code. * * This function is similar to mono_debug_lookup_location(), but we * already looked up the method and also already did the * native address -> IL offset mapping. */ MonoDebugSourceLocation * mono_ppdb_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset) { MonoPPDBFile *ppdb = minfo->handle->ppdb; MonoImage *image = ppdb->image; MonoMethod *method = minfo->method; MonoTableInfo *tables = image->tables; guint32 cols [MONO_METHODBODY_SIZE]; const char *ptr; const char *end; char *docname; int idx, size, docidx, iloffset, delta_il, delta_lines, delta_cols, start_line, start_col, adv_line, adv_col; gboolean first = TRUE, first_non_hidden = TRUE; MonoDebugSourceLocation *location; if (!method->token) return NULL; idx = mono_metadata_token_index (method->token); mono_metadata_decode_row (&tables [MONO_TABLE_METHODBODY], idx-1, cols, MONO_METHODBODY_SIZE); docidx = cols [MONO_METHODBODY_DOCUMENT]; if (!cols [MONO_METHODBODY_SEQ_POINTS]) return NULL; ptr = mono_metadata_blob_heap (image, cols [MONO_METHODBODY_SEQ_POINTS]); size = mono_metadata_decode_blob_size (ptr, &ptr); end = ptr + size; /* Header */ /* LocalSignature */ mono_metadata_decode_value (ptr, &ptr); if (docidx == 0) docidx = mono_metadata_decode_value (ptr, &ptr); docname = get_docname (ppdb, image, docidx); iloffset = 0; start_line = 0; start_col = 0; while (ptr < end) { delta_il = mono_metadata_decode_value (ptr, &ptr); if (!first && delta_il == 0) { /* document-record */ docidx = mono_metadata_decode_value (ptr, &ptr); docname = get_docname (ppdb, image, docidx); continue; } if (!first && iloffset + delta_il > offset) break; iloffset += delta_il; first = FALSE; delta_lines = mono_metadata_decode_value (ptr, &ptr); if (delta_lines == 0) delta_cols = mono_metadata_decode_value (ptr, &ptr); else delta_cols = mono_metadata_decode_signed_value (ptr, &ptr); if (delta_lines == 0 && delta_cols == 0) /* hidden-sequence-point-record */ continue; if (first_non_hidden) { start_line = mono_metadata_decode_value (ptr, &ptr); start_col = mono_metadata_decode_value (ptr, &ptr); } else { adv_line = mono_metadata_decode_signed_value (ptr, &ptr); adv_col = mono_metadata_decode_signed_value (ptr, &ptr); start_line += adv_line; start_col += adv_col; } first_non_hidden = FALSE; } location = g_new0 (MonoDebugSourceLocation, 1); location->source_file = docname; location->row = start_line; location->il_offset = iloffset; return location; }