1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
|
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 < sequencePointCount; index++)
{ if (offsets[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
}
|