Merge pull request #3004 from xmcclure/gc-bridge-various
[mono.git] / mono / metadata / debug-mono-ppdb.c
index cdd5af3f5e80b99a63bfb450f93dfdf70efaac0b..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>
@@ -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,8 +107,12 @@ 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);
@@ -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);
@@ -519,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];
        }
 
@@ -545,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);
                }