/// <summary> /// Gets the sequence points defined for this method /// </summary> /// <param name="offsets">array of IL offsets</param> /// <param name="documents">array of documents</param> /// <param name="lines">start line number array</param> /// <param name="columns">start column number array</param> /// <param name="endLines">end line number array</param> /// <param name="endColumns">start line number array</param> public void GetSequencePoints( // This method needed by PERWAPI int[] offsets, ISymbolDocument[] documents, int[] lines, int[] columns, int[] endLines, int[] endColumns) { int spCount = INVALID; GetAndCheckLength(offsets, ref spCount); GetAndCheckLength(lines, ref spCount); GetAndCheckLength(columns, ref spCount); GetAndCheckLength(endLines, ref spCount); GetAndCheckLength(endColumns, ref spCount); if (spCount == INVALID) { spCount = 0; } int dcCount = documents.Length; ISymUnmanagedDocument[] unDocs = new ISymUnmanagedDocument[dcCount]; private_method.GetSequencePoints( dcCount, out spCount, offsets, unDocs, lines, columns, endLines, endColumns); for (int i = 0; i < dcCount; i++) { documents[i] = new SymbolDocument(unDocs[i]); } return; }
internal static SourceInformation GetSourceInformation(this ISymUnmanagedMethod method) { var sequencePoint = method.GetSequencePoints().OrderBy(s => s.StartLine).FirstOrDefault(); var fileName = sequencePoint.Document.GetName(); var lineNumber = sequencePoint.StartLine; return(new SourceInformation(fileName, lineNumber)); }
/// <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])); }
public void GetSequencePoints(int[] offsets, ISymbolDocument[] documents, int[] lines, int[] columns, int[] endLines, int[] endColumns) { int size = documents.Length; var unmanagedDocs = new ISymUnmanagedDocument[size]; HRESULT.ThrowOnFailure(_unmanaged.GetSequencePoints(size, out size, offsets, unmanagedDocs, lines, columns, endLines, endColumns)); for (int i = 0; i < size; i++) { documents[i] = new SymbolDocument(unmanagedDocs[i]); } }
public int GetSequencePoints( int cPoints, out int pcPoints, int[] offsets, ISymUnmanagedDocument[] documents, int[] lines, int[] columns, int[] endLines, int[] endColumns) { _method.GetSequencePoints(cPoints, out pcPoints, offsets, documents, lines, columns, endLines, endColumns); return(SymUnmanagedReaderExtensions.S_OK); }
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); }
// Write the sequence points for the given method // Sequence points are the map between IL offsets and source lines. // A single method could span multiple files (use C#'s #line directive to see for yourself). private void WriteSequencePoints(ISymUnmanagedMethod method) { writer.WriteStartElement("sequencePoints"); var sequencePoints = method.GetSequencePoints(); // Write out sequence points foreach (var sequencePoint in sequencePoints) { writer.WriteStartElement("entry"); writer.WriteAttributeString("offset", AsILOffset(sequencePoint.Offset)); // If it's a special 0xFeeFee sequence point (eg, "hidden"), // place an attribute on it to make it very easy for tools to recognize. // See http://blogs.msdn.com/jmstall/archive/2005/06/19/FeeFee_SequencePoints.aspx if (sequencePoint.IsHidden) { if (sequencePoint.StartLine != sequencePoint.EndLine || sequencePoint.StartColumn != 0 || sequencePoint.EndColumn != 0) { writer.WriteAttributeString("hidden", "invalid"); } else { writer.WriteAttributeString("hidden", XmlConvert.ToString(true)); } } else { writer.WriteAttributeString("startLine", CultureInvariantToString(sequencePoint.StartLine)); writer.WriteAttributeString("startColumn", CultureInvariantToString(sequencePoint.StartColumn)); writer.WriteAttributeString("endLine", CultureInvariantToString(sequencePoint.EndLine)); writer.WriteAttributeString("endColumn", CultureInvariantToString(sequencePoint.EndColumn)); } //EDMAURER allow there to be PDBs generated for sources that don't have a name (document). int fileRefVal = -1; this.m_fileMapping.TryGetValue(sequencePoint.Document.GetName(), out fileRefVal); writer.WriteAttributeString("document", CultureInvariantToString(fileRefVal)); writer.WriteEndElement(); } writer.WriteEndElement(); // 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 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); } } }
// Write the sequence points for the given method // Sequence points are the map between IL offsets and source lines. // A single method could span multiple files (use C#'s #line directive to see for yourself). private void WriteSequencePoints(ISymUnmanagedMethod method) { var sequencePoints = method.GetSequencePoints(); if (sequencePoints.Length == 0) { return; } _writer.WriteStartElement("sequencePoints"); // Write out sequence points foreach (var sequencePoint in sequencePoints) { _writer.WriteStartElement("entry"); _writer.WriteAttributeString("offset", AsILOffset(sequencePoint.Offset)); if (sequencePoint.IsHidden) { if (sequencePoint.StartLine != sequencePoint.EndLine || sequencePoint.StartColumn != 0 || sequencePoint.EndColumn != 0) { _writer.WriteAttributeString("hidden", "invalid"); } else { _writer.WriteAttributeString("hidden", XmlConvert.ToString(true)); } } else { _writer.WriteAttributeString("startLine", CultureInvariantToString(sequencePoint.StartLine)); _writer.WriteAttributeString("startColumn", CultureInvariantToString(sequencePoint.StartColumn)); _writer.WriteAttributeString("endLine", CultureInvariantToString(sequencePoint.EndLine)); _writer.WriteAttributeString("endColumn", CultureInvariantToString(sequencePoint.EndColumn)); } int documentId; _fileMapping.TryGetValue(sequencePoint.Document.GetName(), out documentId); _writer.WriteAttributeString("document", CultureInvariantToString(documentId)); _writer.WriteEndElement(); } _writer.WriteEndElement(); // sequencepoints }
public void GetSequencePoints(int[] offsets, ISymbolDocument[] documents, int[] lines, int[] columns, int[] endLines, int[] endColumns) { int spCount = 0; if (offsets != null) { spCount = offsets.Length; } else if (documents != null) { spCount = documents.Length; } else if (lines != null) { spCount = lines.Length; } else if (columns != null) { spCount = columns.Length; } else if (endLines != null) { spCount = endLines.Length; } else if (endColumns != null) { spCount = endColumns.Length; } // Don't do anything if they're not really asking for anything. if (spCount == 0) { return; } // Make sure all arrays are the same length. if ((offsets != null) && (spCount != offsets.Length)) { throw new ArgumentException(); } if ((lines != null) && (spCount != lines.Length)) { throw new ArgumentException(); } if ((columns != null) && (spCount != columns.Length)) { throw new ArgumentException(); } if ((endLines != null) && (spCount != endLines.Length)) { throw new ArgumentException(); } if ((endColumns != null) && (spCount != endColumns.Length)) { throw new ArgumentException(); } ISymUnmanagedDocument[] unmanagedDocuments = new ISymUnmanagedDocument[documents.Length]; int cPoints = 0; uint i; m_unmanagedMethod.GetSequencePoints(documents.Length, out cPoints, offsets, unmanagedDocuments, lines, columns, endLines, endColumns); // Create the SymbolDocument form the IntPtr's for (i = 0; i < documents.Length; i++) { documents[i] = new SymbolDocument(unmanagedDocuments[i]); } return; }
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 static void VerifySequencePoints(ISymUnmanagedMethod method, params string[] expected) { AssertEx.Equal(expected, method.GetSequencePoints().Select(sp => sp.IsHidden ? "<hidden>" : $"({sp.StartLine}, {sp.StartColumn}) - ({sp.EndLine}, {sp.EndColumn}) '{sp.Document.GetName()}'")); }
public void GetSequencePoints(int[] offsets, ISymbolDocument[] documents, int[] lines, int[] columns, int[] endLines, int[] endColumns) { // Any array can be null, and the documentation says we must verify the sizes. int arySize = -1; if (offsets != null) { arySize = offsets.Length; } else if (documents != null) { arySize = documents.Length; } else if (lines != null) { arySize = lines.Length; } else if (columns != null) { arySize = columns.Length; } else if (endLines != null) { arySize = endLines.Length; } else if (endColumns != null) { arySize = endColumns.Length; } if (offsets != null && offsets.Length != arySize) { throw new ArgumentException("Invalid array length: offsets"); } if (documents != null && documents.Length != arySize) { throw new ArgumentException("Invalid array length: documents"); } if (lines != null && lines.Length != arySize) { throw new ArgumentException("Invalid array length: lines"); } if (columns != null && columns.Length != arySize) { throw new ArgumentException("Invalid array length: columns"); } if (endLines != null && endLines.Length != arySize) { throw new ArgumentException("Invalid array length: endLines"); } if (endColumns != null && endColumns.Length != arySize) { throw new ArgumentException("Invalid array length: endColumns"); } if (arySize <= 0) { return; } var unDocs = documents == null ? null : new ISymUnmanagedDocument[documents.Length]; uint size; method.GetSequencePoints((uint)arySize, out size, offsets, unDocs, lines, columns, endLines, endColumns); if (unDocs != null) { for (int i = 0; i < unDocs.Length; i++) { documents[i] = unDocs[i] == null ? null : new SymbolDocument(unDocs[i]); } } }