Beispiel #1
0
        /// <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;
        }
Beispiel #2
0
        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]));
        }
Beispiel #4
0
        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]);
            }
        }
Beispiel #5
0
 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);
 }
Beispiel #6
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);
        }
Beispiel #8
0
        // 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
        }
Beispiel #9
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());
        }
        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);
        }
Beispiel #12
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);
                }
            }
        }
Beispiel #14
0
        // 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
        }
Beispiel #15
0
        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;
        }
Beispiel #16
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]);
 }
 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()}'"));
 }
Beispiel #18
0
        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]);
                }
            }
        }