/// <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]));
        }
Example #2
0
            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);
        }
Example #4
0
        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());
        }
Example #5
0
        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);
        }
Example #7
0
 public int GetSequencePointCount(out int retVal)
 {
     return(_method.GetSequencePointCount(out retVal));
 }
Example #8
0
 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]);
 }
Example #9
0
        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);
                }
            }
        }