PDBReader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / Common / AuthoringOM / Compiler / PDBReader.cs / 1305376 / PDBReader.cs

                            namespace System.Workflow.ComponentModel.Compiler 
{
    using System;
    using System.Runtime.InteropServices;
 
    internal sealed class PDBReader : IDisposable
 	{ 
		#region Data Members 

		private const string IMetaDataImportGuid = "7DAC8207-D3AE-4c75-9B67-92801A497D44"; 
		private ISymUnmanagedReader symReader;

 		#endregion
 
		#region Constructor and Dispose
 
 		public PDBReader(string assemblyPath) 
 		{
			object metaDataImport = null; 
 			IMetaDataDispenser dispenser = null;

			try
			{ 
				Guid metaDataImportIID = new Guid(IMetaDataImportGuid);
 
 				dispenser = (IMetaDataDispenser)(new MetaDataDispenser()); 
				dispenser.OpenScope(assemblyPath, 0, ref metaDataImportIID, out metaDataImport);
 
 				this.symReader = (ISymUnmanagedReader)(new CorSymReader_SxS());
 				this.symReader.Initialize(metaDataImport, assemblyPath, null, null);
			}
 			finally 
			{
				// Release COM objects so that files don't remain locked. 
				if (metaDataImport != null) 
 					Marshal.ReleaseComObject(metaDataImport);
 
				if (dispenser != null)
 					Marshal.ReleaseComObject(dispenser);
 			}
		} 

 		~PDBReader() 
		{ 
			Dispose();
		} 

 		void IDisposable.Dispose()
		{
 			Dispose(); 
 			GC.SuppressFinalize(this);
		} 
 
 		private void Dispose()
		{ 
			if (this.symReader != null)
			{
 				Marshal.ReleaseComObject(this.symReader);
				this.symReader = null; 
 			}
 		} 
 
		#endregion
 
 		#region Public methods

		public void GetSourceLocationForOffset(uint methodDef, uint offset, out string fileLocation, out uint line, out uint column)
		{ 
			fileLocation = null;
 			line = 0; 
			column = 0; 

 			ISymUnmanagedMethod symMethod = null; 
 			ISymUnmanagedDocument[] documents = null;
			uint sequencePointCount = 0;

 			try 
			{
				symMethod = this.symReader.GetMethod(methodDef); 
				sequencePointCount = symMethod.GetSequencePointCount(); 

 				documents = new ISymUnmanagedDocument[sequencePointCount]; 
				uint[] offsets = new uint[sequencePointCount];
 				uint[] lines = new uint[sequencePointCount];
 				uint[] columns = new uint[sequencePointCount];
				uint[] endLines = new uint[sequencePointCount]; 
 				uint[] endColumns = new uint[sequencePointCount];
 
				symMethod.GetSequencePoints(sequencePointCount, out sequencePointCount, offsets, documents, lines, columns, endLines, endColumns); 
				
				uint index = 1; 
 				for(; index offset) break; }

 				index = index - 1; 

 				// Work Around: AkashS - The SymReader returns bad line-column data for unconditional branch 
				// instructions. The line number is whacky and the column number is 0. Need to verify why this is so. 
 				// We just look for a good sequence point data, it should be close enough in the source code.
				while (columns[index] == 0 && index > 0) 
					index--;

				while (index < sequencePointCount && columns[index] == 0)
 					index++; 

				// What more can we do? 
 				if (index >= sequencePointCount || columns[index] == 0) 
 					index = 0;
 
				// End Work around


 				line = lines[index]; 
				column = columns[index];
 
				ISymUnmanagedDocument document = documents[index ]; 
				uint urlLength = 261;
 				string url = new string('\0', (int) urlLength); 

				document.GetURL(urlLength, out urlLength, url);
 				fileLocation = url.Substring(0, (int) urlLength - 1);
 			} 
			finally
 			{ 
				// Release COM objects so that files don't remain locked. 
				for (uint i = 0; i < sequencePointCount; i++)
					if (documents[i] != null) 
 						Marshal.ReleaseComObject(documents[i]);

				if (symMethod != null)
 					Marshal.ReleaseComObject(symMethod); 
 			}
		} 
 
 		#endregion
	} 

	#region Interop declarations

	// 
 	// Note:
	//		These interop declaration are sufficient for our purposes of reading the symbol information from 
 	// the PDB. They are not complete otherwise! 
 	//
	[ComImport, Guid("0A3976C5-4529-4ef8-B0B0-42EED37082CD")] 
 	internal class CorSymReader_SxS
	{ }

 
	[
	ComImport, 
 	CoClass(typeof(CorSymReader_SxS)), 
	InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 	Guid("B4CE6286-2A6B-3712-A3B7-1EE1DAD467B5") 
 	]
	internal interface ISymUnmanagedReader
 	{
		// NYI. 
		void GetDocument();
		void GetDocuments(); 
 		void GetUserEntryPoint(); 

		ISymUnmanagedMethod GetMethod(uint methodDef); 
 		
 		// NYI.
		void GetMethodByVersion();
 		void GetVariables(); 
		void GetGlobalVariables();
		void GetMethodFromDocumentPosition(); 
		void GetSymAttribute(); 
 		void GetNamespaces();
		 
 		// Incomplete - We don't use the Stream
 		void Initialize([In, MarshalAs(UnmanagedType.IUnknown)] object metaDataImport, [In, MarshalAs(UnmanagedType.LPWStr)] string pdbPath, [In, MarshalAs(UnmanagedType.LPWStr)] string searchPath, [In, MarshalAs(UnmanagedType.IUnknown)] object stream);

		// NYI. 
 		void UpdateSymbolStore();
		void ReplaceSymbolStore(); 
		void GetSymbolStoreFileName(); 
		void GetMethodsFromDocumentPosition();
 		void GetDocumentVersion(); 
		void GetMethodVersion();
 	}

 
 	[
	ComImport, 
 	InterfaceType(ComInterfaceType.InterfaceIsIUnknown), 
	Guid("B62B923C-B500-3158-A543-24F307A8B7E1")
	] 
	internal interface ISymUnmanagedMethod
 	{
		uint GetToken();
 		uint GetSequencePointCount(); 
 		
		// Incomplete - Don't need to define ISymUnmanagedScope. 
 		object GetRootScope(); 

		// Incomplete - Don't need to define ISymUnmanagedScope. 
		object GetScopeFromOffset(uint offset);

		uint GetOffset([In, MarshalAs(UnmanagedType.IUnknown)] ISymUnmanagedDocument document, uint line, uint column);
 		void GetRanges([In, MarshalAs(UnmanagedType.IUnknown)] ISymUnmanagedDocument document, uint line, uint column, uint rangeCount, [Out] out uint actualRangeCount, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] ranges); 

		// NYI. 
 		void GetParameters(); 
 		
		// NYI. 
 		void GetNamespace();

		void GetSourceStartEnd([In, Out, MarshalAs(UnmanagedType.LPArray)] ISymUnmanagedDocument[] documents, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] lines, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] columns, [Out, MarshalAs(UnmanagedType.Bool)] out bool positionsDefined);
		void GetSequencePoints(uint pointsCount, [Out] out uint actualPointsCount, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] offsets, [In, Out, MarshalAs(UnmanagedType.LPArray)] ISymUnmanagedDocument[] documents, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] lines, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] columns, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] endLines, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] endColumns); 
	}
 
 
 	[
	ComImport, 
 	InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 	Guid("40DE4037-7C81-3E1E-B022-AE1ABFF2CA08")
	]
 	internal interface ISymUnmanagedDocument 
	{
		void GetURL(uint urlLength, [Out] out uint actualUrlLength, [In, Out, MarshalAs(UnmanagedType.LPWStr)] string url); 
		 
 		// The rest are NYI.
		void GetDocumentType(); 
 		void GetLanguage();
 		void GetLanguageVendor();
		void GetCheckSumAlgorithmId();
 		void GetCheckSum(); 
		void FindClosestLine();
		void HasEmbeddedSource(); 
		void GetSourceLength(); 
 		void GetSourceRange();
	} 


 	[
 	ComImport, 
	Guid("E5CB7A31-7512-11d2-89CE-0080C792E5D8")
 	] 
	internal class MetaDataDispenser 
	{
	} 


 	[
	ComImport, 
 	InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 	CoClass(typeof(MetaDataDispenser)), 
	Guid("809C652E-7396-11d2-9771-00A0C9B4D50C") 
 	]
	internal interface IMetaDataDispenser 
	{
		// NYI
 		void DefineScope();
 
		// Incomplete - I don't really need to define IMetaDataImport.
 		void OpenScope([In, MarshalAs(UnmanagedType.LPWStr)] string scope, uint flags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out object unknown); 
 
 		// NYI
		void OpenScopeOnMemory(); 
 	}

	#endregion
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
namespace System.Workflow.ComponentModel.Compiler 
{
    using System;
    using System.Runtime.InteropServices;
 
    internal sealed class PDBReader : IDisposable
 	{ 
		#region Data Members 

		private const string IMetaDataImportGuid = "7DAC8207-D3AE-4c75-9B67-92801A497D44"; 
		private ISymUnmanagedReader symReader;

 		#endregion
 
		#region Constructor and Dispose
 
 		public PDBReader(string assemblyPath) 
 		{
			object metaDataImport = null; 
 			IMetaDataDispenser dispenser = null;

			try
			{ 
				Guid metaDataImportIID = new Guid(IMetaDataImportGuid);
 
 				dispenser = (IMetaDataDispenser)(new MetaDataDispenser()); 
				dispenser.OpenScope(assemblyPath, 0, ref metaDataImportIID, out metaDataImport);
 
 				this.symReader = (ISymUnmanagedReader)(new CorSymReader_SxS());
 				this.symReader.Initialize(metaDataImport, assemblyPath, null, null);
			}
 			finally 
			{
				// Release COM objects so that files don't remain locked. 
				if (metaDataImport != null) 
 					Marshal.ReleaseComObject(metaDataImport);
 
				if (dispenser != null)
 					Marshal.ReleaseComObject(dispenser);
 			}
		} 

 		~PDBReader() 
		{ 
			Dispose();
		} 

 		void IDisposable.Dispose()
		{
 			Dispose(); 
 			GC.SuppressFinalize(this);
		} 
 
 		private void Dispose()
		{ 
			if (this.symReader != null)
			{
 				Marshal.ReleaseComObject(this.symReader);
				this.symReader = null; 
 			}
 		} 
 
		#endregion
 
 		#region Public methods

		public void GetSourceLocationForOffset(uint methodDef, uint offset, out string fileLocation, out uint line, out uint column)
		{ 
			fileLocation = null;
 			line = 0; 
			column = 0; 

 			ISymUnmanagedMethod symMethod = null; 
 			ISymUnmanagedDocument[] documents = null;
			uint sequencePointCount = 0;

 			try 
			{
				symMethod = this.symReader.GetMethod(methodDef); 
				sequencePointCount = symMethod.GetSequencePointCount(); 

 				documents = new ISymUnmanagedDocument[sequencePointCount]; 
				uint[] offsets = new uint[sequencePointCount];
 				uint[] lines = new uint[sequencePointCount];
 				uint[] columns = new uint[sequencePointCount];
				uint[] endLines = new uint[sequencePointCount]; 
 				uint[] endColumns = new uint[sequencePointCount];
 
				symMethod.GetSequencePoints(sequencePointCount, out sequencePointCount, offsets, documents, lines, columns, endLines, endColumns); 
				
				uint index = 1; 
 				for(; index offset) break; }

 				index = index - 1; 

 				// Work Around: AkashS - The SymReader returns bad line-column data for unconditional branch 
				// instructions. The line number is whacky and the column number is 0. Need to verify why this is so. 
 				// We just look for a good sequence point data, it should be close enough in the source code.
				while (columns[index] == 0 && index > 0) 
					index--;

				while (index < sequencePointCount && columns[index] == 0)
 					index++; 

				// What more can we do? 
 				if (index >= sequencePointCount || columns[index] == 0) 
 					index = 0;
 
				// End Work around


 				line = lines[index]; 
				column = columns[index];
 
				ISymUnmanagedDocument document = documents[index ]; 
				uint urlLength = 261;
 				string url = new string('\0', (int) urlLength); 

				document.GetURL(urlLength, out urlLength, url);
 				fileLocation = url.Substring(0, (int) urlLength - 1);
 			} 
			finally
 			{ 
				// Release COM objects so that files don't remain locked. 
				for (uint i = 0; i < sequencePointCount; i++)
					if (documents[i] != null) 
 						Marshal.ReleaseComObject(documents[i]);

				if (symMethod != null)
 					Marshal.ReleaseComObject(symMethod); 
 			}
		} 
 
 		#endregion
	} 

	#region Interop declarations

	// 
 	// Note:
	//		These interop declaration are sufficient for our purposes of reading the symbol information from 
 	// the PDB. They are not complete otherwise! 
 	//
	[ComImport, Guid("0A3976C5-4529-4ef8-B0B0-42EED37082CD")] 
 	internal class CorSymReader_SxS
	{ }

 
	[
	ComImport, 
 	CoClass(typeof(CorSymReader_SxS)), 
	InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 	Guid("B4CE6286-2A6B-3712-A3B7-1EE1DAD467B5") 
 	]
	internal interface ISymUnmanagedReader
 	{
		// NYI. 
		void GetDocument();
		void GetDocuments(); 
 		void GetUserEntryPoint(); 

		ISymUnmanagedMethod GetMethod(uint methodDef); 
 		
 		// NYI.
		void GetMethodByVersion();
 		void GetVariables(); 
		void GetGlobalVariables();
		void GetMethodFromDocumentPosition(); 
		void GetSymAttribute(); 
 		void GetNamespaces();
		 
 		// Incomplete - We don't use the Stream
 		void Initialize([In, MarshalAs(UnmanagedType.IUnknown)] object metaDataImport, [In, MarshalAs(UnmanagedType.LPWStr)] string pdbPath, [In, MarshalAs(UnmanagedType.LPWStr)] string searchPath, [In, MarshalAs(UnmanagedType.IUnknown)] object stream);

		// NYI. 
 		void UpdateSymbolStore();
		void ReplaceSymbolStore(); 
		void GetSymbolStoreFileName(); 
		void GetMethodsFromDocumentPosition();
 		void GetDocumentVersion(); 
		void GetMethodVersion();
 	}

 
 	[
	ComImport, 
 	InterfaceType(ComInterfaceType.InterfaceIsIUnknown), 
	Guid("B62B923C-B500-3158-A543-24F307A8B7E1")
	] 
	internal interface ISymUnmanagedMethod
 	{
		uint GetToken();
 		uint GetSequencePointCount(); 
 		
		// Incomplete - Don't need to define ISymUnmanagedScope. 
 		object GetRootScope(); 

		// Incomplete - Don't need to define ISymUnmanagedScope. 
		object GetScopeFromOffset(uint offset);

		uint GetOffset([In, MarshalAs(UnmanagedType.IUnknown)] ISymUnmanagedDocument document, uint line, uint column);
 		void GetRanges([In, MarshalAs(UnmanagedType.IUnknown)] ISymUnmanagedDocument document, uint line, uint column, uint rangeCount, [Out] out uint actualRangeCount, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] ranges); 

		// NYI. 
 		void GetParameters(); 
 		
		// NYI. 
 		void GetNamespace();

		void GetSourceStartEnd([In, Out, MarshalAs(UnmanagedType.LPArray)] ISymUnmanagedDocument[] documents, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] lines, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] columns, [Out, MarshalAs(UnmanagedType.Bool)] out bool positionsDefined);
		void GetSequencePoints(uint pointsCount, [Out] out uint actualPointsCount, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] offsets, [In, Out, MarshalAs(UnmanagedType.LPArray)] ISymUnmanagedDocument[] documents, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] lines, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] columns, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] endLines, [In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] endColumns); 
	}
 
 
 	[
	ComImport, 
 	InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 	Guid("40DE4037-7C81-3E1E-B022-AE1ABFF2CA08")
	]
 	internal interface ISymUnmanagedDocument 
	{
		void GetURL(uint urlLength, [Out] out uint actualUrlLength, [In, Out, MarshalAs(UnmanagedType.LPWStr)] string url); 
		 
 		// The rest are NYI.
		void GetDocumentType(); 
 		void GetLanguage();
 		void GetLanguageVendor();
		void GetCheckSumAlgorithmId();
 		void GetCheckSum(); 
		void FindClosestLine();
		void HasEmbeddedSource(); 
		void GetSourceLength(); 
 		void GetSourceRange();
	} 


 	[
 	ComImport, 
	Guid("E5CB7A31-7512-11d2-89CE-0080C792E5D8")
 	] 
	internal class MetaDataDispenser 
	{
	} 


 	[
	ComImport, 
 	InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
 	CoClass(typeof(MetaDataDispenser)), 
	Guid("809C652E-7396-11d2-9771-00A0C9B4D50C") 
 	]
	internal interface IMetaDataDispenser 
	{
		// NYI
 		void DefineScope();
 
		// Incomplete - I don't really need to define IMetaDataImport.
 		void OpenScope([In, MarshalAs(UnmanagedType.LPWStr)] string scope, uint flags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out object unknown); 
 
 		// NYI
		void OpenScopeOnMemory(); 
 	}

	#endregion
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK