static int table_locator (const void *a, const void *b) { locator_t *loc = (locator_t *)a; const char *bb = (const char *)b; guint32 table_index = (bb - loc->t->base) / loc->t->row_size; guint32 col; col = mono_metadata_decode_row_col(loc->t, table_index, loc->col_idx); if (loc->idx == col) { loc->result = table_index; return 0; } if (loc->idx < col) return -1; else return 1; }
MonoMethod* mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image) { MonoClass *klass; const MonoTableInfo *methods; MonoMethod *method; int i; /* Handle short names for system classes */ if (!desc->name_space && image == mono_defaults.corlib) { klass = find_system_class (desc->klass); if (klass) return mono_method_desc_search_in_class (desc, klass); } if (desc->name_space && desc->klass) { klass = mono_class_try_load_from_name (image, desc->name_space, desc->klass); if (!klass) return NULL; return mono_method_desc_search_in_class (desc, klass); } /* FIXME: Is this call necessary? We don't use its result. */ mono_image_get_table_info (image, MONO_TABLE_TYPEDEF); methods = mono_image_get_table_info (image, MONO_TABLE_METHOD); for (i = 0; i < mono_table_info_get_rows (methods); ++i) { MonoError error; guint32 token = mono_metadata_decode_row_col (methods, i, MONO_METHOD_NAME); const char *n = mono_metadata_string_heap (image, token); if (strcmp (n, desc->name)) continue; method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error); if (!method) { mono_error_cleanup (&error); continue; } if (mono_method_desc_full_match (desc, method)) return method; } return NULL; }
// 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; }
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; }