[runtime] Introduce kind test functions to cleanup things a bit.
[mono.git] / mono / metadata / debug-mono-ppdb.c
index 4bba9ea33f72768589ebcc4e75ae2623964de672..8357099a551aa9bec2f6c5dcb147724731e1ee5f 100644 (file)
@@ -7,6 +7,7 @@
  *     Mono Project (http://www.mono-project.com)
  *
  * Copyright 2015 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include <config.h>
@@ -88,7 +89,7 @@ get_pe_debug_guid (MonoImage *image, guint8 *out_guid, gint32 *out_age, gint32 *
 static void
 doc_free (gpointer key)
 {
-       MonoDebugSourceInfo *info = key;
+       MonoDebugSourceInfo *info = (MonoDebugSourceInfo *)key;
 
        g_free (info->source_file);
        g_free (info);
@@ -97,7 +98,7 @@ doc_free (gpointer key)
 MonoPPDBFile*
 mono_ppdb_load_file (MonoImage *image, const guint8 *raw_contents, int size)
 {
-       MonoImage *ppdb_image;
+       MonoImage *ppdb_image = NULL;
        const char *filename;
        char *s, *ppdb_filename;
        MonoImageOpenStatus status;
@@ -106,12 +107,16 @@ mono_ppdb_load_file (MonoImage *image, const guint8 *raw_contents, int size)
        gint32 pe_timestamp;
        MonoPPDBFile *ppdb;
 
+       if (!get_pe_debug_guid (image, pe_guid, &pe_age, &pe_timestamp))
+               return NULL;
+
        if (raw_contents) {
-               ppdb_image = mono_image_open_from_data_internal ((char*)raw_contents, size, TRUE, &status, FALSE, TRUE, NULL);
+               if (size > 4 && strncmp ((char*)raw_contents, "BSJB", 4) == 0)
+                       ppdb_image = mono_image_open_from_data_internal ((char*)raw_contents, size, TRUE, &status, FALSE, TRUE, NULL);
        } else {
                /* ppdb files drop the .exe/.dll extension */
                filename = mono_image_get_filename (image);
-               if (strlen (filename) > 4 && (!strcmp (filename + strlen (filename) - 4, ".exe"))) {
+               if (strlen (filename) > 4 && (!strcmp (filename + strlen (filename) - 4, ".exe") || !strcmp (filename + strlen (filename) - 4, ".dll"))) {
                        s = g_strdup (filename);
                        s [strlen (filename) - 4] = '\0';
                        ppdb_filename = g_strdup_printf ("%s.pdb", s);
@@ -132,18 +137,16 @@ mono_ppdb_load_file (MonoImage *image, const guint8 *raw_contents, int size)
         * The same id is stored in the Debug Directory of the PE file, and in the
         * #Pdb stream in the ppdb file.
         */
-       if (get_pe_debug_guid (image, pe_guid, &pe_age, &pe_timestamp)) {
-               PdbStreamHeader *pdb_stream = (PdbStreamHeader*)ppdb_image->heap_pdb.data;
+       PdbStreamHeader *pdb_stream = (PdbStreamHeader*)ppdb_image->heap_pdb.data;
 
-               g_assert (pdb_stream);
+       g_assert (pdb_stream);
 
-               /* The pdb id is a concentation of the pe guid and the timestamp */
-               if (memcmp (pe_guid, pdb_stream->guid, 16) != 0 || memcmp (&pe_timestamp, pdb_stream->guid + 16, 4) != 0) {
-                       g_warning ("Symbol file %s doesn't match image %s", ppdb_image->name,
-                                          image->name);
-                       mono_image_close (ppdb_image);
-                       return NULL;
-               }
+       /* The pdb id is a concentation of the pe guid and the timestamp */
+       if (memcmp (pe_guid, pdb_stream->guid, 16) != 0 || memcmp (&pe_timestamp, pdb_stream->guid + 16, 4) != 0) {
+               g_warning ("Symbol file %s doesn't match image %s", ppdb_image->name,
+                                  image->name);
+               mono_image_close (ppdb_image);
+               return NULL;
        }
 
        ppdb = g_new0 (MonoPPDBFile, 1);
@@ -176,7 +179,7 @@ mono_ppdb_lookup_method (MonoDebugHandle *handle, MonoMethod *method)
 
        mono_debugger_lock ();
 
-       minfo = g_hash_table_lookup (ppdb->method_hash, method);
+       minfo = (MonoDebugMethodInfo *)g_hash_table_lookup (ppdb->method_hash, method);
        if (minfo) {
                mono_debugger_unlock ();
                return minfo;
@@ -208,7 +211,7 @@ get_docinfo (MonoPPDBFile *ppdb, MonoImage *image, int docidx)
        MonoDebugSourceInfo *res, *cached;
 
        mono_debugger_lock ();
-       cached = g_hash_table_lookup (ppdb->doc_hash, GUINT_TO_POINTER (docidx));
+       cached = (MonoDebugSourceInfo *)g_hash_table_lookup (ppdb->doc_hash, GUINT_TO_POINTER (docidx));
        mono_debugger_unlock ();
        if (cached)
                return cached;
@@ -246,7 +249,7 @@ get_docinfo (MonoPPDBFile *ppdb, MonoImage *image, int docidx)
        res->hash = (guint8*)mono_metadata_blob_heap (image, cols [MONO_DOCUMENT_HASH]);
 
        mono_debugger_lock ();
-       cached = g_hash_table_lookup (ppdb->doc_hash, GUINT_TO_POINTER (docidx));
+       cached = (MonoDebugSourceInfo *)g_hash_table_lookup (ppdb->doc_hash, GUINT_TO_POINTER (docidx));
        if (!cached) {
                g_hash_table_insert (ppdb->doc_hash, GUINT_TO_POINTER (docidx), res);
        } else {
@@ -291,7 +294,8 @@ mono_ppdb_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset)
        gboolean first = TRUE, first_non_hidden = TRUE;
        MonoDebugSourceLocation *location;
 
-       g_assert (method->token);
+       if (!method->token)
+               return NULL;
 
        idx = mono_metadata_token_index (method->token);
 
@@ -518,16 +522,39 @@ mono_ppdb_lookup_locals (MonoDebugMethodInfo *minfo)
        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 (scope_idx == tables [MONO_TABLE_LOCALSCOPE].rows) {
+
+       // 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;
-       if (scope_idx == tables [MONO_TABLE_LOCALSCOPE].rows) {
-               locals_end_idx = tables [MONO_TABLE_LOCALVARIABLE].rows;
+
+       // 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];
        }
 
@@ -544,7 +571,7 @@ mono_ppdb_lookup_locals (MonoDebugMethodInfo *minfo)
 
                locals_idx = cols [MONO_LOCALSCOPE_VARIABLELIST];
                if (scope_idx == tables [MONO_TABLE_LOCALSCOPE].rows) {
-                       locals_end_idx = tables [MONO_TABLE_LOCALVARIABLE].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);
                }