g_array_free (sps, TRUE);
}
+
+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];
+ while (TRUE) {
+ 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 ++;
+ }
+ nscopes = scope_idx - start_scope_idx;
+ if (scope_idx == tables [MONO_TABLE_LOCALSCOPE].rows) {
+ // FIXME:
+ g_assert_not_reached ();
+ locals_end_idx = -1;
+ } else {
+ 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) {
+ // FIXME:
+ g_assert_not_reached ();
+ } 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);
+MonoDebugLocalsInfo*
+mono_ppdb_lookup_locals (MonoDebugMethodInfo *minfo);
+
#endif
return res;
}
-
-/*
- * mono_debug_symfile_free_locals:
- *
- * Free all the data allocated by mono_debug_symfile_lookup_locals ().
- */
-void
-mono_debug_symfile_free_locals (MonoDebugLocalsInfo *info)
-{
- int i;
-
- for (i = 0; i < info->num_locals; ++i)
- g_free (info->locals [i].name);
- g_free (info->locals);
- g_free (info->code_blocks);
- g_free (info);
-}
MONO_API MonoDebugLocalsInfo*
mono_debug_symfile_lookup_locals (MonoDebugMethodInfo *minfo);
-MONO_API void
-mono_debug_symfile_free_locals (MonoDebugLocalsInfo *info);
-
void
mono_debug_symfile_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points);
MonoMethod *
mono_get_method_checked (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context, MonoError *error);
+guint32
+mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index);
+
#endif /* __MONO_METADATA_INTERNALS_H__ */
MONO_MT_BLOB_IDX, /* SequencePoints */
MONO_MT_END,
-#define NULL_SCHEMA_OFFSET METHODBODY_SCHEMA_OFFSET + 2
+#define LOCALSCOPE_SCHEMA_OFFSET METHODBODY_SCHEMA_OFFSET + 2
+ MONO_MT_TABLE_IDX, /* Method */
+ MONO_MT_TABLE_IDX, /* ImportScope */
+ MONO_MT_TABLE_IDX, /* VariableList */
+ MONO_MT_TABLE_IDX, /* ConstantList */
+ MONO_MT_UINT32, /* StartOffset */
+ MONO_MT_UINT32, /* Length */
+ MONO_MT_END,
+
+#define LOCALVARIABLE_SCHEMA_OFFSET LOCALSCOPE_SCHEMA_OFFSET + 7
+ MONO_MT_UINT16, /* Attributes */
+ MONO_MT_UINT16, /* Index */
+ MONO_MT_STRING_IDX, /* Name */
+ MONO_MT_END,
+
+#define NULL_SCHEMA_OFFSET LOCALVARIABLE_SCHEMA_OFFSET + 4
MONO_MT_END
};
NULL_SCHEMA_OFFSET,
NULL_SCHEMA_OFFSET,
DOCUMENT_SCHEMA_OFFSET, /* 0x30 */
- METHODBODY_SCHEMA_OFFSET
+ METHODBODY_SCHEMA_OFFSET,
+ LOCALSCOPE_SCHEMA_OFFSET,
+ LOCALVARIABLE_SCHEMA_OFFSET
};
#ifdef HAVE_ARRAY_ELEM_INIT
g_assert (i == 0);
field_size = idx_size (meta, MONO_TABLE_GENERICPARAM);
break;
-
+ case MONO_TABLE_LOCALSCOPE:
+ switch (i) {
+ case 0:
+ // FIXME: This table is in another file
+ field_size = idx_size (meta, MONO_TABLE_METHOD);
+ break;
+ case 1:
+ field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE);
+ break;
+ case 2:
+ field_size = idx_size (meta, MONO_TABLE_LOCALVARIABLE);
+ break;
+ case 3:
+ field_size = idx_size (meta, MONO_TABLE_LOCALCONSTANT);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
default:
g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex, i);
}
return loc.result;
}
+/*
+ * mono_metadata_localscope_from_methoddef:
+ * @meta: metadata context
+ * @index: methoddef index
+ *
+ * Returns: the 1-based index into the LocalScope table of the first
+ * scope which belongs to the method described by @index.
+ * Returns 0 if no such row is found.
+ */
+guint32
+mono_metadata_localscope_from_methoddef (MonoImage *meta, guint32 index)
+{
+ MonoTableInfo *tdef = &meta->tables [MONO_TABLE_LOCALSCOPE];
+ locator_t loc;
+
+ if (!tdef->base)
+ return 0;
+
+ loc.idx = index;
+ loc.col_idx = MONO_LOCALSCOPE_METHOD;
+ loc.t = tdef;
+
+ if (!mono_binary_search (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+ return 0;
+
+ /* Find the first entry by searching backwards */
+ while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_LOCALSCOPE_METHOD) == index))
+ loc.result --;
+
+ return loc.result + 1;
+}
+
#ifdef DEBUG
static void
mono_backtrace (int limit)
void
mono_debug_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points);
+MONO_API void
+mono_debug_free_locals (MonoDebugLocalsInfo *info);
+
#endif /* __MONO_DEBUG_DEBUGGER_H__ */
* mono_debug_lookup_locals:
*
* Return information about the local variables of MINFO.
- * The result should be freed using mono_debug_symfile_free_locals ().
+ * The result should be freed using mono_debug_free_locals ().
*/
MonoDebugLocalsInfo*
mono_debug_lookup_locals (MonoMethod *method)
mono_debugger_lock ();
minfo = mono_debug_lookup_method_internal (method);
- if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
+ if (!minfo || !minfo->handle) {
mono_debugger_unlock ();
return NULL;
}
- res = mono_debug_symfile_lookup_locals (minfo);
+ if (minfo->handle->ppdb) {
+ res = mono_ppdb_lookup_locals (minfo);
+ } else {
+ if (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile))
+ res = NULL;
+ else
+ res = mono_debug_symfile_lookup_locals (minfo);
+ }
mono_debugger_unlock ();
return res;
}
+/*
+ * mono_debug_free_locals:
+ *
+ * Free all the data allocated by mono_debug_lookup_locals ().
+ */
+void
+mono_debug_free_locals (MonoDebugLocalsInfo *info)
+{
+ int i;
+
+ for (i = 0; i < info->num_locals; ++i)
+ g_free (info->locals [i].name);
+ g_free (info->locals);
+ g_free (info->code_blocks);
+ g_free (info);
+}
+
/**
* mono_debug_free_source_location:
* @location: A `MonoDebugSourceLocation'.
MONO_METHODBODY_SIZE
};
+enum {
+ MONO_LOCALSCOPE_METHOD,
+ MONO_LOCALSCOPE_IMPORTSCOPE,
+ MONO_LOCALSCOPE_VARIABLELIST,
+ MONO_LOCALSCOPE_CONSTANTLIST,
+ MONO_LOCALSCOPE_STARTOFFSET,
+ MONO_LOCALSCOPE_LENGTH,
+ MONO_LOCALSCOPE_SIZE
+};
+
+enum {
+ MONO_LOCALVARIABLE_ATTRIBUTES,
+ MONO_LOCALVARIABLE_INDEX,
+ MONO_LOCALVARIABLE_NAME,
+ MONO_LOCALVARIABLE_SIZE
+};
+
/*
* Coded Tokens
* The _BITS entry is for the bits used in the token.
case CMD_METHOD_GET_LOCALS_INFO: {
int i, j, num_locals;
MonoDebugLocalsInfo *locals;
+ int *locals_map = NULL;
header = mono_method_get_header (method);
if (!header)
return ERR_INVALID_ARGUMENT;
- buffer_add_int (buf, header->num_locals);
-
- /* Types */
- for (i = 0; i < header->num_locals; ++i)
- buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [i]));
-
- /* Names */
locals = mono_debug_lookup_locals (method);
- if (locals)
- num_locals = locals->num_locals;
- else
- num_locals = 0;
- for (i = 0; i < header->num_locals; ++i) {
- for (j = 0; j < num_locals; ++j)
- if (locals->locals [j].index == i)
- break;
- if (j < num_locals)
- buffer_add_string (buf, locals->locals [j].name);
- else
- buffer_add_string (buf, "");
- }
-
- /* Scopes */
- for (i = 0; i < header->num_locals; ++i) {
- for (j = 0; j < num_locals; ++j)
- if (locals->locals [j].index == i)
- break;
- if (j < num_locals && locals->locals [j].block) {
- buffer_add_int (buf, locals->locals [j].block->start_offset);
- buffer_add_int (buf, locals->locals [j].block->end_offset);
- } else {
+ if (!locals) {
+ buffer_add_int (buf, header->num_locals);
+ /* Types */
+ for (i = 0; i < header->num_locals; ++i) {
+ buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [i]));
+ }
+ /* Names */
+ for (i = 0; i < header->num_locals; ++i) {
+ char lname [128];
+ sprintf (lname, "V_%d", i);
+ buffer_add_string (buf, lname);
+ }
+ /* Scopes */
+ for (i = 0; i < header->num_locals; ++i) {
buffer_add_int (buf, 0);
buffer_add_int (buf, header->code_size);
}
+ } else {
+ /* Maps between the IL locals index and the index in locals->locals */
+ locals_map = g_new0 (int, header->num_locals);
+ for (i = 0; i < header->num_locals; ++i)
+ locals_map [i] = -1;
+ num_locals = locals->num_locals;
+ for (i = 0; i < num_locals; ++i) {
+ g_assert (locals->locals [i].index < header->num_locals);
+ locals_map [locals->locals [i].index] = i;
+ }
+ buffer_add_int (buf, num_locals);
+
+ /* Types */
+ for (i = 0; i < header->num_locals; ++i) {
+ if (locals_map [i] != -1)
+ buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [i]));
+ }
+
+ /* Names */
+ for (i = 0; i < header->num_locals; ++i) {
+ if (locals_map [i] != -1)
+ buffer_add_string (buf, locals->locals [locals_map [i]].name);
+ }
+
+ /* Scopes */
+ for (i = 0; i < header->num_locals; ++i) {
+ if (locals_map [i] != -1) {
+ j = locals_map [i];
+ if (locals->locals [j].block) {
+ buffer_add_int (buf, locals->locals [j].block->start_offset);
+ buffer_add_int (buf, locals->locals [j].block->end_offset);
+ } else {
+ buffer_add_int (buf, 0);
+ buffer_add_int (buf, header->code_size);
+ }
+ }
+ }
}
mono_metadata_free_mh (header);
if (locals)
- mono_debug_symfile_free_locals (locals);
+ mono_debug_free_locals (locals);
+ g_free (locals_map);
break;
}
}
if (locals_info)
- mono_debug_symfile_free_locals (locals_info);
+ mono_debug_free_locals (locals_info);
/* Subprogram end */
emit_uleb128 (w, 0x0);