/// <summary> /// Get a string representing the source location for the given IL offset and method /// </summary> /// <param name="method">The method of interest</param> /// <param name="ilOffset">The offset into the IL</param> /// <returns>A string of the format [filepath]:[line] (eg. "C:\temp\foo.cs:123"), or null /// if a matching PDB couldn't be found</returns> /// <remarks>Thows various COMExceptions (from DIA SDK error values) if a PDB couldn't be opened/read</remarks> public SourceLoc GetSourceLoc(MethodBase method, int ilOffset) { // Get the symbol reader corresponding to the module of the supplied method string modulePath = method.Module.FullyQualifiedName; ISymUnmanagedReader symReader = GetSymbolReaderForFile(modulePath); if (symReader == null) { return(null); // no PDBs } ISymUnmanagedMethod symMethod = symReader.GetMethod(new SymbolToken(method.MetadataToken)); // Get all the sequence points for the method int count = symMethod.GetSequencePointCount(); ISymUnmanagedDocument[] docs = new ISymUnmanagedDocument[count]; int[] startLines = new int[count]; int[] ilOffsets = new int[count]; int[] endLines = new int[count]; int[] startCols = new int[count]; int[] endCols = new int[count]; int outPoints; symMethod.GetSequencePoints(count, out outPoints, ilOffsets, docs, startLines, startCols, endLines, endCols); // Find the closest sequence point to the requested offset // Sequence points are returned sorted by offset so we're looking for the last one with // an offset less than or equal to the requested offset. // Note that this won't necessarily match the real source location exactly if // the code was jit-compiled with optimizations. int i; for (i = 0; i < count; i++) { if (ilOffsets[i] > ilOffset) { break; } } // Found the first mismatch, back up if it wasn't the first if (i > 0) { i--; } // Now return the source file and line number for this sequence point StringBuilder url = new StringBuilder(512); int len; docs[i].GetURL(url.Capacity, out len, url); return(new SourceLoc(url.ToString(), startLines[i], endLines[i], startCols[i], endCols[i])); }
private static bool TryGetDocsAndLines( ISymUnmanagedMethod methodSymbols, CompetitionState competitionState, out ISymUnmanagedDocument[] documents, out int[] startLines) { documents = Array <ISymUnmanagedDocument> .Empty; startLines = Array <int> .Empty; try { int numAvailable; var hr = methodSymbols.GetSequencePointCount(out numAvailable); ThrowExceptionForHR(hr); documents = new ISymUnmanagedDocument[numAvailable]; startLines = new int[numAvailable]; if (numAvailable > 0) { var offsets = new int[numAvailable]; var startColumns = new int[numAvailable]; var endLines = new int[numAvailable]; var endColumns = new int[numAvailable]; int numRead; hr = methodSymbols.GetSequencePoints( numAvailable, out numRead, offsets, documents, startLines, startColumns, endLines, endColumns); ThrowExceptionForHR(hr); if (numRead != numAvailable) { throw new COMException($"Read only {numRead} of {numAvailable} sequence points."); } } } catch (COMException ex) { // ReSharper disable once PossibleNullReferenceException competitionState.WriteExceptionMessage( MessageSource.Analyser, MessageSeverity.ExecutionError, "Could not parse method symbols.", ex); return(false); } return(startLines.Length > 0); }
// ISymUnmanagedMethod public static SequencePoint[] GetSequencePoints(this ISymUnmanagedMethod symMethod, int codesize) { uint count = symMethod.GetSequencePointCount(); ISymUnmanagedDocument[] documents = new ISymUnmanagedDocument[count]; uint[] offsets = new uint[count]; uint[] lines = new uint[count]; uint[] columns = new uint[count]; uint[] endLines = new uint[count]; uint[] endColumns = new uint[count]; symMethod.GetSequencePoints( count, out count, offsets, documents, lines, columns, endLines, endColumns ); var sequencePoints = new SequencePoint[count]; var urls = documents.Distinct().ToDictionary(d => d, d => d.GetURL()); var sums = documents.Distinct().ToDictionary(d => d, d => d.GetCheckSum()); uint token = symMethod.GetToken(); for (int i = 0; i < count; i++) { sequencePoints[i] = new SequencePoint() { MethodDefToken = token, ILRanges = new [] { new ILRange((int)offsets[i], i + 1 < count ? (int)offsets[i + 1] : codesize) }, Filename = urls[documents[i]], FileCheckSum = sums[documents[i]], StartLine = (int)lines[i], StartColumn = (int)columns[i], EndLine = (int)endLines[i], EndColumn = (int)endColumns[i] }; } return(sequencePoints); }
internal static ImmutableArray <SymUnmanagedSequencePoint> GetSequencePoints(this ISymUnmanagedMethod method) { // NB: method.GetSequencePoints(0, out numAvailable, ...) always returns 0. int numAvailable; int hr = method.GetSequencePointCount(out numAvailable); SymUnmanagedReaderExtensions.ThrowExceptionForHR(hr); if (numAvailable == 0) { return(ImmutableArray <SymUnmanagedSequencePoint> .Empty); } int[] offsets = new int[numAvailable]; ISymUnmanagedDocument[] documents = new ISymUnmanagedDocument[numAvailable]; int[] startLines = new int[numAvailable]; int[] startColumns = new int[numAvailable]; int[] endLines = new int[numAvailable]; int[] endColumns = new int[numAvailable]; int numRead; hr = method.GetSequencePoints(numAvailable, out numRead, offsets, documents, startLines, startColumns, endLines, endColumns); SymUnmanagedReaderExtensions.ThrowExceptionForHR(hr); if (numRead != numAvailable) { throw new InvalidOperationException(string.Format("Read only {0} of {1} sequence points.", numRead, numAvailable)); } var builder = ArrayBuilder <SymUnmanagedSequencePoint> .GetInstance(numRead); for (int i = 0; i < numRead; i++) { builder.Add(new SymUnmanagedSequencePoint( offsets[i], documents[i], startLines[i], startColumns[i], endLines[i], endColumns[i])); } return(builder.ToImmutableAndFree()); }
public static IEnumerable <SymUnmanagedSequencePoint> GetSequencePoints(this ISymUnmanagedMethod method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } // NB: method.GetSequencePoints(0, out numAvailable, ...) always returns 0. int numAvailable; ThrowExceptionForHR(method.GetSequencePointCount(out numAvailable)); if (numAvailable == 0) { yield break; } int[] offsets = new int[numAvailable]; ISymUnmanagedDocument[] documents = new ISymUnmanagedDocument[numAvailable]; int[] startLines = new int[numAvailable]; int[] startColumns = new int[numAvailable]; int[] endLines = new int[numAvailable]; int[] endColumns = new int[numAvailable]; int numRead; ThrowExceptionForHR( method.GetSequencePoints( numAvailable, out numRead, offsets, documents, startLines, startColumns, endLines, endColumns)); ValidateItems(numRead, offsets.Length); for (int i = 0; i < numRead; i++) { yield return(new SymUnmanagedSequencePoint( offsets[i], documents[i], startLines[i], startColumns[i], endLines[i], endColumns[i])); } }
// ISymUnmanagedMethod public static SequencePoint[] GetSequencePoints(this ISymUnmanagedMethod symMethod) { uint count = symMethod.GetSequencePointCount(); ISymUnmanagedDocument[] documents = new ISymUnmanagedDocument[count]; uint[] offsets = new uint[count]; uint[] lines = new uint[count]; uint[] columns = new uint[count]; uint[] endLines = new uint[count]; uint[] endColumns = new uint[count]; symMethod.GetSequencePoints( count, out count, offsets, documents, lines, columns, endLines, endColumns ); SequencePoint[] sequencePoints = new SequencePoint[count]; for (int i = 0; i < count; i++) { sequencePoints[i] = new SequencePoint() { Document = documents[i], Offset = offsets[i], Line = lines[i], Column = columns[i], EndLine = endLines[i], EndColumn = endColumns[i] }; } return(sequencePoints); }
public int GetSequencePointCount(out int retVal) { return(_method.GetSequencePointCount(out retVal)); }
internal void RecordSequencePoints(ISymUnmanagedMethod methodInfo) { if(methodInfo == null || this.contextForOffset != null) return; this.contextForOffset = new TrivialHashtable(); uint count = methodInfo.GetSequencePointCount(); IntPtr[] docPtrs = new IntPtr[count]; uint[] startLines = new uint[count]; uint[] startCols = new uint[count]; uint[] endLines = new uint[count]; uint[] endCols = new uint[count]; uint[] offsets = new uint[count]; uint numPoints; methodInfo.GetSequencePoints(count, out numPoints, offsets, docPtrs, startLines, startCols, endLines, endCols); Debug.Assert(count == numPoints); for(int i = 0; i < count; i++) { //The magic hex constant below works around weird data reported from GetSequencePoints. //The constant comes from ILDASM's source code, which performs essentially the same test. const uint Magic = 0xFEEFEE; if(startLines[i] >= Magic || endLines[i] >= Magic) continue; UnmanagedDocument doc = new UnmanagedDocument(docPtrs[i]); this.contextForOffset[(int)offsets[i] + 1] = new SourceContext(doc, doc.GetOffset(startLines[i], startCols[i]), doc.GetOffset(endLines[i], endCols[i])); } for(int i = 0; i < count; i++) System.Runtime.InteropServices.Marshal.Release(docPtrs[i]); }
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); } } }
public void GetSourceLocationForOffset(uint methodDef, uint offset, out string fileLocation, out uint line, out uint column) { fileLocation = null; line = 0; column = 0; ISymUnmanagedMethod o = null; ISymUnmanagedDocument[] documents = null; uint pointsCount = 0; try { o = this.symReader.GetMethod(methodDef); pointsCount = o.GetSequencePointCount(); documents = new ISymUnmanagedDocument[pointsCount]; uint[] offsets = new uint[pointsCount]; uint[] lines = new uint[pointsCount]; uint[] columns = new uint[pointsCount]; uint[] endLines = new uint[pointsCount]; uint[] endColumns = new uint[pointsCount]; o.GetSequencePoints(pointsCount, out pointsCount, offsets, documents, lines, columns, endLines, endColumns); uint index = 1; while (index < pointsCount) { if (offsets[index] > offset) { break; } index++; } index--; while ((columns[index] == 0) && (index > 0)) { index--; } while ((index < pointsCount) && (columns[index] == 0)) { index++; } if ((index >= pointsCount) || (columns[index] == 0)) { index = 0; } line = lines[index]; column = columns[index]; ISymUnmanagedDocument document = documents[index]; uint urlLength = 0x105; string url = new string('\0', (int)urlLength); document.GetURL(urlLength, out urlLength, url); fileLocation = url.Substring(0, ((int)urlLength) - 1); } finally { for (uint i = 0; i < pointsCount; i++) { if (documents[i] != null) { Marshal.ReleaseComObject(documents[i]); } } if (o != null) { Marshal.ReleaseComObject(o); } } }