X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fdebug-mono-ppdb.c;h=ab302a084d325e7437551da00004a201a154406f;hb=3478b0aa86b50db14d8cd90bf19dae27f5df100b;hp=46cf3468e5db286e541bc687d15daa36a15249d2;hpb=0a7461e32c3b99563c515a0079923a4471e44240;p=mono.git diff --git a/mono/metadata/debug-mono-ppdb.c b/mono/metadata/debug-mono-ppdb.c index 46cf3468e5d..ab302a084d3 100644 --- a/mono/metadata/debug-mono-ppdb.c +++ b/mono/metadata/debug-mono-ppdb.c @@ -1,5 +1,6 @@ -/* - * debug-mono-ppdb.c: Support for the portable PDB symbol +/** + * \file + * Support for the portable PDB symbol * file format * * @@ -7,6 +8,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 @@ -19,12 +21,12 @@ #include #include #include -#include -#include +#include #include #include #include #include +#include #include "debug-mono-ppdb.h" @@ -94,20 +96,41 @@ doc_free (gpointer key) g_free (info); } +static MonoPPDBFile* +create_ppdb_file (MonoImage *ppdb_image) +{ + MonoPPDBFile *ppdb; + + ppdb = g_new0 (MonoPPDBFile, 1); + ppdb->image = ppdb_image; + ppdb->doc_hash = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) doc_free); + ppdb->method_hash = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_free); + return ppdb; +} + 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; guint8 pe_guid [16]; gint32 pe_age; gint32 pe_timestamp; - MonoPPDBFile *ppdb; + + if (image->tables [MONO_TABLE_DOCUMENT].rows) { + /* Embedded ppdb */ + mono_image_addref (image); + return create_ppdb_file (image); + } + + 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,26 +155,19 @@ 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); - ppdb->image = ppdb_image; - ppdb->doc_hash = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) doc_free); - ppdb->method_hash = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_free); - - return ppdb; + return create_ppdb_file (ppdb_image); } void @@ -268,13 +284,12 @@ get_docname (MonoPPDBFile *ppdb, MonoImage *image, int docidx) /** * mono_ppdb_lookup_location: - * @minfo: A `MonoDebugMethodInfo' which can be retrieved by - * mono_debug_lookup_method(). - * @offset: IL offset within the corresponding method's CIL code. + * \param minfo A \c MonoDebugMethodInfo which can be retrieved by mono_debug_lookup_method(). + * \param offset IL offset within the corresponding method's CIL code. * * This function is similar to mono_debug_lookup_location(), but we * already looked up the method and also already did the - * `native address -> IL offset' mapping. + * native address -> IL offset mapping. */ MonoDebugSourceLocation * mono_ppdb_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset) @@ -291,7 +306,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 +534,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 +583,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); } @@ -568,3 +607,126 @@ mono_ppdb_lookup_locals (MonoDebugMethodInfo *minfo) return res; } + +/* +* We use this to pass context information to the row locator +*/ +typedef struct { + int idx; /* The index that we are trying to locate */ + int col_idx; /* The index in the row where idx may be stored */ + MonoTableInfo *t; /* pointer to the table */ + guint32 result; +} locator_t; + +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; +} + +static gboolean +compare_guid (guint8* guid1, guint8* guid2) { + for (int i = 0; i < 16; i++) { + if (guid1 [i] != guid2 [i]) + return FALSE; + } + return TRUE; +} + +// 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; +} + +MonoDebugMethodAsyncInfo* +mono_ppdb_lookup_method_async_debug_info (MonoDebugMethodInfo *minfo) +{ + MonoMethod *method = minfo->method; + MonoPPDBFile *ppdb = minfo->handle->ppdb; + MonoImage *image = ppdb->image; + + // Guid is taken from Roslyn source code: + // https://github.com/dotnet/roslyn/blob/1ad4b58/src/Dependencies/CodeAnalysis.Metadata/PortableCustomDebugInfoKinds.cs#L9 + guint8 async_method_stepping_information_guid [16] = { 0xC5, 0x2A, 0xFD, 0x54, 0x25, 0xE9, 0x1A, 0x40, 0x9C, 0x2A, 0xF9, 0x4F, 0x17, 0x10, 0x72, 0xF8 }; + char const *blob = lookup_custom_debug_information (image, method->token, 0, async_method_stepping_information_guid); + if (!blob) + return NULL; + int blob_len = mono_metadata_decode_blob_size (blob, &blob); + MonoDebugMethodAsyncInfo* res = g_new0 (MonoDebugMethodAsyncInfo, 1); + char const *pointer = blob; + + // Format of this blob is taken from Roslyn source code: + // https://github.com/dotnet/roslyn/blob/1ad4b58/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs#L566 + + pointer += 4;//catch_handler_offset + while (pointer - blob < blob_len) { + res->num_awaits++; + pointer += 8;//yield_offsets+resume_offsets + mono_metadata_decode_value (pointer, &pointer);//move_next_method_token + } + g_assert(pointer - blob == blob_len); //Check that we used all blob data + pointer = blob; //reset pointer after we figured num_awaits + + res->yield_offsets = g_new (uint32_t, res->num_awaits); + res->resume_offsets = g_new (uint32_t, res->num_awaits); + res->move_next_method_token = g_new (uint32_t, res->num_awaits); + + res->catch_handler_offset = read32 (pointer); pointer += 4; + for (int i = 0; i < res->num_awaits; i++) { + res->yield_offsets [i] = read32 (pointer); pointer += 4; + res->resume_offsets [i] = read32 (pointer); pointer += 4; + res->move_next_method_token [i] = mono_metadata_decode_value (pointer, &pointer); + } + return res; +}