Example #1
0
        private unsafe void WriteEditAndContinueLambdaMap(CustomDebugInfoRecord record)
        {
            Debug.Assert(record.Kind == CustomDebugInfoKind.EditAndContinueLambdaMap);

            writer.WriteStartElement("encLambdaMap");
            try
            {
                if (record.Data.Length == 0)
                {
                    return;
                }

                int methodOrdinal = -1;
                int syntaxOffsetBaseline = -1;
                int closureCount;

                fixed (byte* blobPtr = &record.Data.ToArray()[0])
                {
                    var blobReader = new BlobReader(blobPtr, record.Data.Length);

                    if (!blobReader.TryReadCompressedInteger(out methodOrdinal))
                    {
                        writer.WriteElementString("methodOrdinal", "?");
                        writer.WriteEndElement();
                        return;
                    }

                    // [-1, inf)
                    methodOrdinal--;
                    writer.WriteElementString("methodOrdinal", methodOrdinal.ToString());

                    if (!blobReader.TryReadCompressedInteger(out syntaxOffsetBaseline))
                    {
                        writer.WriteElementString("baseline", "?");
                        writer.WriteEndElement();
                        return;
                    }

                    syntaxOffsetBaseline = -syntaxOffsetBaseline;
                    if (!blobReader.TryReadCompressedInteger(out closureCount))
                    {
                        writer.WriteElementString("closureCount", "?");
                        writer.WriteEndElement();
                        return;
                    }

                    for (int i = 0; i < closureCount; i++)
                    {
                        writer.WriteStartElement("closure");
                        try
                        {
                            int syntaxOffset;
                            if (!blobReader.TryReadCompressedInteger(out syntaxOffset))
                            {
                                writer.WriteElementString("offset", "?");
                                break;
                            }

                            writer.WriteAttributeString("offset", (syntaxOffset + syntaxOffsetBaseline).ToString());
                        }
                        finally
                        {
                            writer.WriteEndElement();
                        }
                    }

                    while (blobReader.RemainingBytes > 0)
                    {
                        writer.WriteStartElement("lambda");
                        try
                        {
                            int syntaxOffset;
                            if (!blobReader.TryReadCompressedInteger(out syntaxOffset))
                            {
                                writer.WriteElementString("offset", "?");
                                return;
                            }

                            writer.WriteAttributeString("offset", (syntaxOffset + syntaxOffsetBaseline).ToString());

                            int closureOrdinal;
                            if (!blobReader.TryReadCompressedInteger(out closureOrdinal))
                            {
                                writer.WriteElementString("closure", "?");
                                return;
                            }

                            closureOrdinal--;
                            if (closureOrdinal != -1)
                            {
                                writer.WriteAttributeString("closure",
                                    closureOrdinal.ToString() + (closureOrdinal < -1 || closureOrdinal >= closureCount ? " (invalid)" : ""));
                            }
                        }
                        finally
                        {
                            writer.WriteEndElement();
                        }
                    }
                }
            }
            finally
            {
                writer.WriteEndElement(); //encLocalSlotMap
            }
        }
Example #2
0
        /// <summary>
        /// Contains a list of buckets, each of which contains a number of flags, a slot ID, and a name.
        /// TODO: comment when the structure is understood.
        /// </summary>
        /// <remarks>
        /// Appears when there are dynamic locals.
        /// </remarks>
        private void WriteDynamicLocalsCustomDebugInfo(CustomDebugInfoRecord record)
        {
            Debug.Assert(record.Kind == CustomDebugInfoKind.DynamicLocals);

            writer.WriteStartElement("dynamicLocals");

            var buckets = CDI.DecodeDynamicLocalsRecord(record.Data);

            foreach (DynamicLocalBucket bucket in buckets)
            {
                ulong flags = bucket.Flags;
                int flagCount = bucket.FlagCount;

                PooledStringBuilder pooled = PooledStringBuilder.GetInstance();
                StringBuilder flagsBuilder = pooled.Builder;
                for (int f = 0; f < flagCount; f++)
                {
                    flagsBuilder.Append((flags >> f) & 1UL);
                }

                writer.WriteStartElement("bucket");
                writer.WriteAttributeString("flagCount", flagCount.ToString());
                writer.WriteAttributeString("flags", pooled.ToStringAndFree());
                writer.WriteAttributeString("slotId", bucket.SlotId.ToString());
                writer.WriteAttributeString("localName", bucket.Name);
                writer.WriteEndElement(); //bucket
            }

            writer.WriteEndElement(); //dynamicLocals
        }
Example #3
0
        private unsafe void WriteEditAndContinueLocalSlotMap(CustomDebugInfoRecord record)
        {
            Debug.Assert(record.Kind == CustomDebugInfoKind.EditAndContinueLocalSlotMap);

            writer.WriteStartElement("encLocalSlotMap");
            try
            {
                int syntaxOffsetBaseline = -1;

                fixed (byte* compressedSlotMapPtr = &record.Data.ToArray()[0])
                {
                    var blobReader = new BlobReader(compressedSlotMapPtr, record.Data.Length);

                    while (blobReader.RemainingBytes > 0)
                    {
                        byte b = blobReader.ReadByte();

                        if (b == 0xff)
                        {
                            if (!blobReader.TryReadCompressedInteger(out syntaxOffsetBaseline))
                            {
                                writer.WriteElementString("baseline", "?");
                                return;
                            }

                            syntaxOffsetBaseline = -syntaxOffsetBaseline;
                            continue;
                        }

                        writer.WriteStartElement("slot");

                        if (b == 0)
                        {
                            // short-lived temp, no info
                            writer.WriteAttributeString("kind", "temp");
                        }
                        else
                        {
                            int synthesizedKind = (b & 0x3f) - 1;
                            bool hasOrdinal = (b & (1 << 7)) != 0;

                            int syntaxOffset;
                            bool badSyntaxOffset = !blobReader.TryReadCompressedInteger(out syntaxOffset);
                            syntaxOffset += syntaxOffsetBaseline;

                            int ordinal = 0;
                            bool badOrdinal = hasOrdinal && !blobReader.TryReadCompressedInteger(out ordinal);

                            writer.WriteAttributeString("kind", synthesizedKind.ToString());
                            writer.WriteAttributeString("offset", badSyntaxOffset ? "?" : syntaxOffset.ToString());

                            if (badOrdinal || hasOrdinal)
                            {
                                writer.WriteAttributeString("ordinal", badOrdinal ? "?" : ordinal.ToString());
                            }
                        }

                        writer.WriteEndElement();
                    }
                }
            }
            finally
            {
                writer.WriteEndElement(); //encLocalSlotMap
            }
        }
Example #4
0
        /// <summary>
        /// Contains a name string.
        /// TODO: comment when the structure is understood.
        /// </summary>
        /// <remarks>
        /// Appears when are iterator methods.
        /// </remarks>
        private void WriteForwardIteratorCustomDebugInfo(CustomDebugInfoRecord record)
        {
            Debug.Assert(record.Kind == CustomDebugInfoKind.ForwardIterator);

            writer.WriteStartElement("forwardIterator");

            string name = CDI.DecodeForwardIteratorRecord(record.Data);

            writer.WriteAttributeString("name", name);

            writer.WriteEndElement(); //forwardIterator
        }
Example #5
0
        /// <summary>
        /// Appears when iterator locals have to lifted into fields.  Contains a list of buckets with
        /// start and end offsets (presumably, into IL).
        /// TODO: comment when the structure is understood.
        /// </summary>
        /// <remarks>
        /// Appears when there are locals in iterator methods.
        /// </remarks>
        private void WriteStatemachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoRecord record)
        {
            Debug.Assert(record.Kind == CustomDebugInfoKind.StateMachineHoistedLocalScopes);

            writer.WriteStartElement("hoistedLocalScopes");

            var scopes = CDI.DecodeStateMachineHoistedLocalScopesRecord(record.Data);

            foreach (StateMachineHoistedLocalScope scope in scopes)
            {
                writer.WriteStartElement("slot");
                writer.WriteAttributeString("startOffset", AsILOffset(scope.StartOffset));
                writer.WriteAttributeString("endOffset", AsILOffset(scope.EndOffset));
                writer.WriteEndElement(); //bucket
            }

            writer.WriteEndElement();
        }
Example #6
0
        /// <summary>
        /// This indicates that further information can be obtained by looking at the custom debug
        /// info of another method (specified by token).
        /// </summary>
        /// <remarks>
        /// Appears when there are extern aliases and edit-and-continue is disabled.
        /// Emitting tokens makes tests more fragile.
        /// </remarks>
        private void WriteForwardToModuleCustomDebugInfo(CustomDebugInfoRecord record)
        {
            Debug.Assert(record.Kind == CustomDebugInfoKind.ForwardToModuleInfo);

            writer.WriteStartElement("forwardToModule");

            int token = CDI.DecodeForwardRecord(record.Data);
            WriteMethodAttributes(token, isReference: true);

            writer.WriteEndElement(); //forwardToModule
        }
Example #7
0
        /// <summary>
        /// For each namespace declaration enclosing a method (innermost-to-outermost), there is a count
        /// of the number of imports in that declaration.
        /// </summary>
        /// <remarks>
        /// There's always at least one entry (for the global namespace).
        /// </remarks>
        private void WriteUsingCustomDebugInfo(CustomDebugInfoRecord record)
        {
            Debug.Assert(record.Kind == CustomDebugInfoKind.UsingInfo);

            writer.WriteStartElement("using");

            ImmutableArray<short> counts = CDI.DecodeUsingRecord(record.Data);

            foreach (short importCount in counts)
            {
                writer.WriteStartElement("namespace");
                writer.WriteAttributeString("usingCount", importCount.ToString());
                writer.WriteEndElement(); //namespace
            }

            writer.WriteEndElement(); //using
        }
Example #8
0
        /// <summary>
        /// If the custom debug info is in a format that we don't understand, then we will
        /// just print a standard record header followed by the rest of the record as a
        /// single hex string.
        /// </summary>
        private void WriteUnknownCustomDebugInfo(CustomDebugInfoRecord record)
        {
            writer.WriteStartElement("unknown");
            writer.WriteAttributeString("kind", record.Kind.ToString());
            writer.WriteAttributeString("version", record.Version.ToString());

            PooledStringBuilder pooled = PooledStringBuilder.GetInstance();
            StringBuilder builder = pooled.Builder;
            foreach (byte b in record.Data)
            {
                builder.AppendFormat("{0:X2}", b);
            }

            writer.WriteAttributeString("payload", pooled.ToStringAndFree());

            writer.WriteEndElement(); //unknown
        }