Browse Source

[Ppdb] Support for reading CustomDebugInformation and more specifically AsyncMethodDebugInfo

David Karlaš 9 years ago
parent
commit
da69fcc7f6

+ 48 - 0
mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs

@@ -13,6 +13,7 @@ using System.Threading.Tasks;
 using System.Collections.Generic;
 using System.Linq;
 using System.Net.Sockets;
+using System.Threading.Tasks;
 using MonoTests.Helpers;
 
 public class TestsBase
@@ -431,6 +432,7 @@ public class Tests : TestsBase, ITest2
 		ss_recursive_chaotic ();
 		ss_fp_clobber ();
 		ss_no_frames ();
+		ss_await ();
 	}
 
 	[MethodImplAttribute (MethodImplOptions.NoInlining)]
@@ -717,6 +719,52 @@ public class Tests : TestsBase, ITest2
 		ss_no_frames_3 ();
 	}
 
+	[MethodImplAttribute (MethodImplOptions.NoInlining)]
+	public static void ss_await ()
+	{
+		ss_await_1 ().Wait ();//in
+		ss_await_1 ().Wait ();//over
+		ss_await_1 ().Wait ();//out before
+		ss_await_1 ().Wait ();//out after
+		ss_await_1_exc (true, true).Wait ();//in
+		ss_await_1_exc (true, true).Wait ();//over
+		ss_await_1_exc (true, true).Wait ();//out
+		try {
+			ss_await_1_exc (true, false).Wait ();//in
+		} catch { }
+		try {
+			ss_await_1_exc (true, false).Wait ();//over
+		} catch { }
+		try {
+			ss_await_1_exc (true, false).Wait ();//out
+		} catch { }
+	}
+
+	[MethodImplAttribute (MethodImplOptions.NoInlining)]
+	public static async Task<int> ss_await_1 () {
+		var a = 1;
+		await Task.Delay (10);
+		return a + 2;
+	}
+
+	[MethodImplAttribute (MethodImplOptions.NoInlining)]
+	public static async Task<int> ss_await_1_exc (bool exc, bool handled)
+	{
+		var a = 1;
+		await Task.Delay (10);
+		if (exc) {
+			if (handled) {
+				try {
+					throw new Exception ();
+				} catch {
+				}
+			} else {
+				throw new Exception ();
+			}
+		}
+		return a + 2;
+	}
+
 	[MethodImplAttribute (MethodImplOptions.NoInlining)]
 	public static void ss_no_frames_2 () {
 	}

+ 136 - 0
mcs/class/Mono.Debugger.Soft/Test/dtest.cs

@@ -943,6 +943,142 @@ public class DebuggerTests
 		f = e.Thread.GetFrames ()[0];
 		AssertValue (7.0, f.GetValue (f.Method.GetParameters ()[0]));
 		req.Disable ();
+
+		e = run_until ("ss_await");
+		e = step_in_await ("ss_await", e);//ss_await_1 ().Wait ();//in
+		e = step_in_await ("MoveNext", e);//{
+		e = step_in_await ("MoveNext", e);//var a = 1;
+		e = step_in_await ("MoveNext", e);//await Task.Delay (10);
+		e = step_in_await ("MoveNext", e);//return a + 2;
+		e = step_in_await ("MoveNext", e);//}
+		e = step_in_await ("ss_await", e);//ss_await_1 ().Wait ();//in
+
+		e = step_in_await ("ss_await", e);//ss_await_1 ().Wait ();//over
+		e = step_in_await ("MoveNext", e);//{
+		e = step_over_await ("MoveNext", e);//var a = 1;
+		e = step_over_await ("MoveNext", e);//await Task.Delay (10);
+		e = step_over_await ("MoveNext", e);//return a + 2;
+		e = step_over_await ("MoveNext", e);//}
+		e = step_over_await ("ss_await", e);//ss_await_1 ().Wait ();//over
+
+		e = step_in_await ("ss_await", e);//ss_await_1 ().Wait ();//out before
+		e = step_in_await ("MoveNext", e);//{
+		e = step_out_await ("ss_await", e);//ss_await_1 ().Wait ();//out before
+
+		e = step_in_await ("ss_await", e);//ss_await_1 ().Wait ();//out after
+		e = step_in_await ("MoveNext", e);//{
+		e = step_in_await ("MoveNext", e);//var a = 1;
+		e = step_in_await ("MoveNext", e);//await Task.Delay (10);
+		e = step_in_await ("MoveNext", e);//return a + 2;
+		e = step_out_await ("ss_await", e);//ss_await_1 ().Wait ();//out after
+
+		e = step_in_await ("ss_await", e);//ss_await_1_exc (true, true).Wait ();//in
+		e = step_in_await ("MoveNext", e);//{
+		e = step_in_await ("MoveNext", e);//var a = 1;
+		e = step_in_await ("MoveNext", e);//await Task.Delay (10);
+		e = step_in_await ("MoveNext", e);//if (exc)
+		e = step_in_await ("MoveNext", e);//{
+		e = step_in_await ("MoveNext", e);//if (handled)
+		e = step_in_await ("MoveNext", e);//{
+		e = step_in_await ("MoveNext", e);//try {
+		e = step_in_await ("MoveNext", e);//throw new Exception ();
+		e = step_in_await ("MoveNext", e);//catch
+		e = step_in_await ("MoveNext", e);//{
+		e = step_in_await ("MoveNext", e);//}
+		e = step_in_await ("MoveNext", e);//}
+		e = step_in_await ("MoveNext", e);//}
+		e = step_in_await ("MoveNext", e);//return a + 2;
+		e = step_in_await ("MoveNext", e);//}
+		e = step_in_await ("ss_await", e);//ss_await_1_exc (true, true).Wait ();//in
+
+		e = step_in_await ("ss_await", e);//ss_await_1_exc (true, true).Wait ();//over
+		e = step_in_await ("MoveNext", e);//{
+		e = step_over_await ("MoveNext", e);//var a = 1;
+		e = step_over_await ("MoveNext", e);//await Task.Delay (10);
+		e = step_over_await ("MoveNext", e);//if (exc)
+		e = step_over_await ("MoveNext", e);//{
+		e = step_over_await ("MoveNext", e);//if (handled)
+		e = step_over_await ("MoveNext", e);//{
+		e = step_over_await ("MoveNext", e);//try {
+		e = step_over_await ("MoveNext", e);//throw new Exception ();
+		e = step_over_await ("MoveNext", e);//catch
+		e = step_over_await ("MoveNext", e);//{
+		e = step_over_await ("MoveNext", e);//}
+		e = step_over_await ("MoveNext", e);//}
+		e = step_over_await ("MoveNext", e);//}
+		e = step_over_await ("MoveNext", e);//return a + 2;
+		e = step_over_await ("MoveNext", e);//}
+		e = step_over_await ("ss_await", e);//ss_await_1_exc (true, true).Wait ();//over
+
+		e = step_in_await ("ss_await", e);//ss_await_1_exc (true, true).Wait ();//out
+		e = step_in_await ("MoveNext", e);//{
+		e = step_out_await ("ss_await", e);//ss_await_1_exc (true, true).Wait ();//out
+
+		e = step_in_await ("ss_await", e);//try {
+		e = step_in_await ("ss_await", e);//ss_await_1_exc (true, false).Wait ();//in
+		e = step_in_await ("MoveNext", e);//{
+		e = step_in_await ("MoveNext", e);//var a = 1;
+		e = step_in_await ("MoveNext", e);//await Task.Delay (10);
+		e = step_in_await ("MoveNext", e);//if (exc)
+		e = step_in_await ("MoveNext", e);//{
+		e = step_in_await ("MoveNext", e);//if (handled)
+		e = step_in_await ("MoveNext", e);//} else {
+		e = step_in_await ("MoveNext", e);//throw new Exception ();
+		e = step_in_await ("ss_await", e);//catch
+		e = step_in_await ("ss_await", e);//{
+		e = step_in_await ("ss_await", e);//}
+		e = step_in_await ("ss_await", e);//try {
+
+		e = step_in_await ("ss_await", e);//ss_await_1_exc (true, false).Wait ();//over
+		e = step_in_await ("MoveNext", e);//{
+		e = step_over_await ("MoveNext", e);//var a = 1;
+		e = step_over_await ("MoveNext", e);//await Task.Delay (10);
+		e = step_over_await ("MoveNext", e);//if (exc)
+		e = step_over_await ("MoveNext", e);//{
+		e = step_over_await ("MoveNext", e);//if (handled)
+		e = step_over_await ("MoveNext", e);//} else {
+		e = step_over_await ("MoveNext", e);//throw new Exception ();
+		e = step_over_await ("ss_await", e);//catch
+		e = step_over_await ("ss_await", e);//{
+		e = step_over_await ("ss_await", e);//}
+		e = step_over_await ("ss_await", e);//try {
+
+		e = step_in_await ("ss_await", e);//ss_await_1_exc (true, false).Wait ();//out
+		e = step_in_await ("MoveNext", e);//{
+		e = step_out_await ("ss_await", e);//ss_await_1_exc (true, true).Wait ();//out
+	}
+
+	Event step_in_await (string method, Event e)
+	{
+		if (step_req != null)
+			step_req.Disable ();
+		create_step (e);
+		step_req.AssemblyFilter = new List<AssemblyMirror> () { entry_point.DeclaringType.Assembly };
+		var ef = step_into ();
+		assert_location (ef, method);
+		return ef;
+	}
+
+	Event step_over_await (string method, Event e)
+	{
+		if (step_req != null)
+			step_req.Disable ();
+		create_step (e);
+		step_req.AssemblyFilter = new List<AssemblyMirror> () { entry_point.DeclaringType.Assembly };
+		var ef = step_over ();
+		assert_location (ef, method);
+		return ef;
+	}
+
+	Event step_out_await (string method, Event e)
+	{
+		if (step_req != null)
+			step_req.Disable ();
+		create_step (e);
+		step_req.AssemblyFilter = new List<AssemblyMirror> () { entry_point.DeclaringType.Assembly };
+		var ef = step_out ();
+		assert_location (ef, method);
+		return ef;
 	}
 
 	[Test]

+ 1 - 1
mono/metadata/blob.h

@@ -105,7 +105,7 @@ typedef enum {
 	MONO_TABLE_LOCALVARIABLE,
 	MONO_TABLE_LOCALCONSTANT,
 	MONO_TABLE_IMPORTSCOPE,
-	MONO_TABLE_ASYNCMETHOD,
+	MONO_TABLE_STATEMACHINEMETHOD,
 	MONO_TABLE_CUSTOMDEBUGINFORMATION
 
 #define MONO_TABLE_LAST MONO_TABLE_CUSTOMDEBUGINFORMATION

+ 124 - 0
mono/metadata/debug-mono-ppdb.c

@@ -26,6 +26,7 @@
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/class-internals.h>
 #include <mono/metadata/cil-coff.h>
+#include <mono/utils/bsearch.h>
 
 #include "debug-mono-ppdb.h"
 
@@ -595,3 +596,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;
+}

+ 3 - 0
mono/metadata/debug-mono-ppdb.h

@@ -35,4 +35,7 @@ mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrAr
 MonoDebugLocalsInfo*
 mono_ppdb_lookup_locals (MonoDebugMethodInfo *minfo);
 
+MonoDebugMethodAsyncInfo*
+mono_ppdb_lookup_method_async_debug_info (MonoDebugMethodInfo *minfo);
+
 #endif

+ 11 - 0
mono/metadata/debug-mono-symfile.h

@@ -103,6 +103,17 @@ struct _MonoDebugLocalsInfo {
 	MonoDebugCodeBlock *code_blocks;
 };
 
+/*
+* Information about method await yield and resume offsets retrieved from a symbol file.
+*/
+struct _MonoDebugMethodAsyncInfo {
+	uint32_t catch_handler_offset;
+	int num_awaits;
+	uint32_t *yield_offsets;
+	uint32_t *resume_offsets;
+	uint32_t *move_next_method_token;
+};
+
 struct _MonoDebugLineNumberEntry {
 	uint32_t il_offset;
 	uint32_t native_offset;

+ 80 - 6
mono/metadata/metadata.c

@@ -109,7 +109,10 @@ enum {
 	MONO_MT_HS_IDX,
 
 	/* ResolutionScope coded index: Module, ModuleRef, AssemblytRef, TypeRef */
-	MONO_MT_RS_IDX
+	MONO_MT_RS_IDX,
+
+	/* CustomDebugInformation parent encoded index */
+	MONO_MT_HASCUSTDEBUG_IDX
 };
 
 const static unsigned char TableSchemas [] = {
@@ -397,7 +400,28 @@ const static unsigned char TableSchemas [] = {
 	MONO_MT_STRING_IDX,  /* Name */
 	MONO_MT_END,
 
-#define NULL_SCHEMA_OFFSET LOCALVARIABLE_SCHEMA_OFFSET + 4
+#define LOCALCONSTANT_SCHEMA_OFFSET LOCALVARIABLE_SCHEMA_OFFSET + 4
+	MONO_MT_STRING_IDX,  /* Name (String heap index) */
+	MONO_MT_BLOB_IDX,    /* Signature (Blob heap index, LocalConstantSig blob) */
+	MONO_MT_END,
+
+#define IMPORTSCOPE_SCHEMA_OFFSET LOCALCONSTANT_SCHEMA_OFFSET + 3
+	MONO_MT_TABLE_IDX, /* Parent (ImportScope row id or nil) */
+	MONO_MT_BLOB_IDX,  /* Imports (Blob index, encoding: Imports blob) */
+	MONO_MT_END,
+
+#define ASYNCMETHOD_SCHEMA_OFFSET IMPORTSCOPE_SCHEMA_OFFSET + 3
+	MONO_MT_TABLE_IDX, /* MoveNextMethod (MethodDef row id) */
+	MONO_MT_TABLE_IDX, /* KickoffMethod (MethodDef row id) */
+	MONO_MT_END,
+
+#define CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET ASYNCMETHOD_SCHEMA_OFFSET + 3
+	MONO_MT_HASCUSTDEBUG_IDX, /* Parent (HasCustomDebugInformation coded index) */
+	MONO_MT_GUID_IDX,  /* Kind (Guid heap index) */
+	MONO_MT_BLOB_IDX,  /* Value (Blob heap index) */
+	MONO_MT_END,
+
+#define NULL_SCHEMA_OFFSET CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET + 4
 	MONO_MT_END
 };
 
@@ -455,7 +479,11 @@ table_description [] = {
 	DOCUMENT_SCHEMA_OFFSET, /* 0x30 */
 	METHODBODY_SCHEMA_OFFSET,
 	LOCALSCOPE_SCHEMA_OFFSET,
-	LOCALVARIABLE_SCHEMA_OFFSET
+	LOCALVARIABLE_SCHEMA_OFFSET,
+	LOCALCONSTANT_SCHEMA_OFFSET,
+	IMPORTSCOPE_SCHEMA_OFFSET,
+	ASYNCMETHOD_SCHEMA_OFFSET,
+	CUSTOMDEBUGINFORMATION_SCHEMA_OFFSET
 };
 
 #ifdef HAVE_ARRAY_ELEM_INIT
@@ -673,8 +701,13 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit
 				break;
 			case MONO_TABLE_METHODBODY:
 				g_assert (i == 0);
-				field_size = idx_size (meta, MONO_TABLE_DOCUMENT);
-				break;
+				field_size = idx_size (meta, MONO_TABLE_DOCUMENT); break;
+			case MONO_TABLE_IMPORTSCOPE:
+				g_assert(i == 0);
+				field_size = idx_size (meta, MONO_TABLE_IMPORTSCOPE); break;
+			case MONO_TABLE_STATEMACHINEMETHOD:
+				g_assert(i == 0 || i == 1);
+				field_size = idx_size(meta, MONO_TABLE_METHOD); break;
 			default:
 				g_error ("Can't handle MONO_MT_TABLE_IDX for table %d element %d", tableindex, i);
 			}
@@ -727,11 +760,52 @@ mono_metadata_compute_size (MonoImage *meta, int tableindex, guint32 *result_bit
 			n = MAX (n, meta->tables [MONO_TABLE_FILE].rows);
 			n = MAX (n, meta->tables [MONO_TABLE_EXPORTEDTYPE].rows);
 			n = MAX (n, meta->tables [MONO_TABLE_MANIFESTRESOURCE].rows);
+			n = MAX (n, meta->tables [MONO_TABLE_GENERICPARAM].rows);
+			n = MAX (n, meta->tables [MONO_TABLE_GENERICPARAMCONSTRAINT].rows);
+			n = MAX (n, meta->tables [MONO_TABLE_METHODSPEC].rows);
 
 			/* 5 bits to encode */
 			field_size = rtsize (meta, n, 16-5);
 			break;
 
+			/*
+			* HasCustomAttribute: points to any table but
+			* itself.
+			*/
+
+		case MONO_MT_HASCUSTDEBUG_IDX:
+			n = MAX(meta->tables[MONO_TABLE_METHOD].rows,
+				meta->tables[MONO_TABLE_FIELD].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_TYPEREF].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_TYPEDEF].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_PARAM].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_INTERFACEIMPL].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_MEMBERREF].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_MODULE].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_DECLSECURITY].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_PROPERTY].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_EVENT].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_STANDALONESIG].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_MODULEREF].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_TYPESPEC].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_ASSEMBLY].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_ASSEMBLYREF].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_FILE].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_EXPORTEDTYPE].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_MANIFESTRESOURCE].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_GENERICPARAM].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_GENERICPARAMCONSTRAINT].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_METHODSPEC].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_DOCUMENT].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_LOCALSCOPE].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_LOCALVARIABLE].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_LOCALCONSTANT].rows);
+			n = MAX(n, meta->tables[MONO_TABLE_IMPORTSCOPE].rows);
+
+			/* 5 bits to encode */
+			field_size = rtsize(meta, n, 16 - 5);
+			break;
+
 			/*
 			 * CustomAttributeType: TypeDef, TypeRef, MethodDef, 
 			 * MemberRef and String.  
@@ -1125,7 +1199,7 @@ mono_metadata_decode_blob_size (const char *xptr, const char **rptr)
  * @rptr: the new position of the pointer
  *
  * This routine decompresses 32-bit values as specified in the "Blob and
- * Signature" section (22.2)
+ * Signature" section (23.2)
  *
  * Returns: the decoded value
  */

+ 3 - 0
mono/metadata/mono-debug-debugger.h

@@ -20,4 +20,7 @@ mono_debug_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrA
 MONO_API void
 mono_debug_free_locals (MonoDebugLocalsInfo *info);
 
+void
+mono_debug_free_method_async_debug_info (MonoDebugMethodAsyncInfo *info);
+
 #endif /* __MONO_DEBUG_DEBUGGER_H__ */

+ 46 - 0
mono/metadata/mono-debug.c

@@ -848,6 +848,52 @@ mono_debug_free_locals (MonoDebugLocalsInfo *info)
 	g_free (info);
 }
 
+/*
+* mono_debug_lookup_method_async_debug_info:
+*
+*   Return information about the async stepping information of method.
+* The result should be freed using mono_debug_free_async_debug_info ().
+*/
+MonoDebugMethodAsyncInfo*
+mono_debug_lookup_method_async_debug_info (MonoMethod *method)
+{
+	MonoDebugMethodInfo *minfo;
+	MonoDebugMethodAsyncInfo *res = NULL;
+
+	if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
+		return NULL;
+
+	mono_debugger_lock ();
+	minfo = mono_debug_lookup_method_internal (method);
+	if (!minfo || !minfo->handle) {
+		mono_debugger_unlock ();
+		return NULL;
+	}
+
+	if (minfo->handle->ppdb)
+		res = mono_ppdb_lookup_method_async_debug_info (minfo);
+
+	mono_debugger_unlock ();
+
+	return res;
+}
+
+/*
+ * mono_debug_free_method_async_debug_info:
+ *
+ *   Free all the data allocated by mono_debug_lookup_method_async_debug_info ().
+ */
+void
+mono_debug_free_method_async_debug_info (MonoDebugMethodAsyncInfo *info)
+{
+	if (info->num_awaits) {
+		g_free (info->yield_offsets);
+		g_free (info->resume_offsets);
+		g_free (info->move_next_method_token);
+	}
+	g_free (info);
+}
+
 /**
  * mono_debug_free_source_location:
  * @location: A `MonoDebugSourceLocation'.

+ 4 - 0
mono/metadata/mono-debug.h

@@ -30,6 +30,7 @@ typedef struct _MonoDebugClassEntry		MonoDebugClassEntry;
 
 typedef struct _MonoDebugMethodInfo		MonoDebugMethodInfo;
 typedef struct _MonoDebugLocalsInfo		MonoDebugLocalsInfo;
+typedef struct _MonoDebugMethodAsyncInfo	MonoDebugMethodAsyncInfo;
 typedef struct _MonoDebugSourceLocation		MonoDebugSourceLocation;
 
 typedef struct _MonoDebugList			MonoDebugList;
@@ -186,6 +187,9 @@ mono_debug_add_delegate_trampoline (void* code, int size);
 MONO_API MonoDebugLocalsInfo*
 mono_debug_lookup_locals (MonoMethod *method);
 
+MonoDebugMethodAsyncInfo*
+mono_debug_lookup_method_async_debug_info (MonoMethod *method);
+
 MonoDebugSourceLocation *
 mono_debug_method_lookup_location (MonoDebugMethodInfo *minfo, int il_offset);
 

+ 7 - 0
mono/metadata/row-indexes.h

@@ -339,6 +339,13 @@ enum {
 	MONO_LOCALVARIABLE_SIZE
 };
 
+enum {
+	MONO_CUSTOMDEBUGINFORMATION_PARENT,
+	MONO_CUSTOMDEBUGINFORMATION_KIND,
+	MONO_CUSTOMDEBUGINFORMATION_VALUE,
+	MONO_CUSTOMDEBUGINFORMATION_SIZE
+};
+
 /*
  * Coded Tokens
  * The _BITS entry is for the bits used in the token.