[runtime] Implement support for locals info for portable pdb files.
authorZoltan Varga <vargaz@gmail.com>
Mon, 11 May 2015 07:24:14 +0000 (03:24 -0400)
committerZoltan Varga <vargaz@gmail.com>
Mon, 11 May 2015 07:24:14 +0000 (03:24 -0400)
mono/metadata/debug-mono-ppdb.c
mono/metadata/debug-mono-ppdb.h
mono/metadata/debug-mono-symfile.c
mono/metadata/debug-mono-symfile.h
mono/metadata/metadata-internals.h
mono/metadata/metadata.c
mono/metadata/mono-debug-debugger.h
mono/metadata/mono-debug.c
mono/metadata/row-indexes.h
mono/mini/debugger-agent.c
mono/mini/dwarfwriter.c

index 0bdd39cfb5e7020584306accdb36f16c05c60e57..660ffeebf4fb89bcd709f59dfee56b14c34b5707 100644 (file)
@@ -392,3 +392,88 @@ mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrAr
 
        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;
+}
index 0ac9f51d940e13cf750d24dbfda2dd73687757c6..d90120e58073dbee24e1631f149b39f2682d04c1 100644 (file)
@@ -31,4 +31,7 @@ mono_ppdb_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset);
 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
index 0378dfe5b1db22b4929dc6a577ba99b70737ca8a..39c348cd7be38615dd5a94bcbdfa7c331aa227d1 100644 (file)
@@ -834,20 +834,3 @@ mono_debug_symfile_lookup_locals (MonoDebugMethodInfo *minfo)
 
        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);
-}
index c9f04d73ed82e2aeecd30a6a23959a1fb12f9ef2..684168994b43e3f6952476f075fa02a230fea3f7 100644 (file)
@@ -154,9 +154,6 @@ mono_debug_symfile_lookup_method   (MonoDebugHandle          *handle,
 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);
 
index c1ff3bdf750a6b2caec095eb8822d9ab1f2e0472..8e68399cfa43daa517bfc98e1c53b430182eaf52 100644 (file)
@@ -823,5 +823,8 @@ mono_method_get_signature_checked (MonoMethod *method, MonoImage *image, guint32
 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__ */
 
index 8d977d4c3bd262494ea01f103b5f05299c104855..5697b59d3380fd4e18ed4fb82b3d808ace99e8c3 100644 (file)
@@ -379,7 +379,22 @@ const static unsigned char TableSchemas [] = {
        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
 };
 
@@ -435,7 +450,9 @@ table_description [] = {
        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
@@ -627,7 +644,26 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit
                                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);
                        }
@@ -4309,6 +4345,38 @@ mono_metadata_declsec_from_index (MonoImage *meta, guint32 index)
        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)
index cbacec5e46e07dfd1fda75d584fe01abed0d1298..6b04225241975cb6f86e66766f536c637d8ec821 100644 (file)
@@ -17,4 +17,7 @@ void            mono_debugger_unlock                        (void);
 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__ */
index 2b5110c87bcf2890eb5460adf4246f20da0148b8..fb12af22a48bae251ef9ac7ed750a952ce00b87f 100644 (file)
@@ -779,7 +779,7 @@ mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDoma
  * 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)
@@ -792,17 +792,41 @@ 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'.
index 79ec5f40f69267059aca2061af730bb828c81ea8..ccca123d00e372dbd30f25e19839e920cd3a807e 100644 (file)
@@ -321,6 +321,23 @@ enum {
        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.
index d74715d0daf41478b80fbdd9528911cffaaf5a33..187d89a1c4e50bc150c81000767a358de2ea46bf 100644 (file)
@@ -8412,50 +8412,73 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
        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;
        }
index 0543d1b0d35ec8dc8eb57ca00f8b537b379c21cc..b2c99a04ad70c087e981883ff9ffaf24f3915cdb 100644 (file)
@@ -2004,7 +2004,7 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
        }
 
        if (locals_info)
-               mono_debug_symfile_free_locals (locals_info);
+               mono_debug_free_locals (locals_info);
 
        /* Subprogram end */
        emit_uleb128 (w, 0x0);