Example #1
0
        internal static void SerializeCustomDebugInformation(
            ref CustomDebugInfoEncoder encoder,
            EditAndContinueMethodDebugInformation debugInfo
            )
        {
            // PERF: note that we pass debugInfo as explicit parameter
            //       that is intentional to avoid capturing debugInfo as that
            //       would result in a lot of delegate allocations here that are otherwise can be avoided.
            if (!debugInfo.LocalSlots.IsDefaultOrEmpty)
            {
                encoder.AddRecord(
                    CustomDebugInfoKind.EditAndContinueLocalSlotMap,
                    debugInfo,
                    (info, builder) => info.SerializeLocalSlots(builder)
                    );
            }

            if (!debugInfo.Lambdas.IsDefaultOrEmpty)
            {
                encoder.AddRecord(
                    CustomDebugInfoKind.EditAndContinueLambdaMap,
                    debugInfo,
                    (info, builder) => info.SerializeLambdaMap(builder)
                    );
            }
        }
Example #2
0
        private static PooledBlobBuilder SerializeRecord(
            byte kind,
            EditAndContinueMethodDebugInformation debugInfo,
            Action <EditAndContinueMethodDebugInformation, BlobBuilder> recordSerializer)
        {
            var cmw = PooledBlobBuilder.GetInstance();

            cmw.WriteByte(CDI.CdiVersion);
            cmw.WriteByte(kind);
            cmw.WriteByte(0);

            // alignment size and length (will be patched)
            var alignmentSizeAndLengthWriter = new BlobWriter(cmw.ReserveBytes(sizeof(byte) + sizeof(uint)));

            recordSerializer(debugInfo, cmw);

            int  length        = cmw.Count;
            int  alignedLength = 4 * ((length + 3) / 4);
            byte alignmentSize = (byte)(alignedLength - length);

            cmw.WriteBytes(0, alignmentSize);

            // fill in alignment size and length:
            alignmentSizeAndLengthWriter.WriteByte(alignmentSize);
            alignmentSizeAndLengthWriter.WriteUInt32((uint)alignedLength);

            return(cmw);
        }
Example #3
0
        public static unsafe EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(this ISymUnmanagedReader3 symReader, MethodDefinitionHandle handle)
        {
            const int S_OK = 0;

            if (symReader is ISymUnmanagedReader4 symReader4)
            {
                int hr = symReader4.GetPortableDebugMetadata(out byte *metadata, out int size);
                Marshal.ThrowExceptionForHR(hr);

                if (hr == S_OK)
                {
                    var pdbReader = new MetadataReader(metadata, size);

                    ImmutableArray <byte> GetCdiBytes(Guid kind) =>
                    TryGetCustomDebugInformation(pdbReader, handle, kind, out var info) ? pdbReader.GetBlobContent(info.Value) : default(ImmutableArray <byte>);

                    return(EditAndContinueMethodDebugInformation.Create(
                               compressedSlotMap: GetCdiBytes(PortableCustomDebugInfoKinds.EncLocalSlotMap),
                               compressedLambdaMap: GetCdiBytes(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap)));
                }
            }

            var cdi = CustomDebugInfoUtilities.GetCustomDebugInfoBytes(symReader, handle, methodVersion: 1);

            if (cdi == null)
            {
                return(EditAndContinueMethodDebugInformation.Create(default(ImmutableArray <byte>), default(ImmutableArray <byte>)));
            }

            return(GetEncMethodDebugInfo(cdi));
        }
Example #4
0
        public void EditAndContinueLambdaAndClosureMap_NegativeSyntaxOffsets()
        {
            var slots = ImmutableArray <LocalSlotDebugInfo> .Empty;

            var closures = ImmutableArray.Create(
                new ClosureDebugInfo(-100),
                new ClosureDebugInfo(10),
                new ClosureDebugInfo(-200));

            var lambdas = ImmutableArray.Create(
                new LambdaDebugInfo(20, 1),
                new LambdaDebugInfo(-50, 0),
                new LambdaDebugInfo(-180, -1));

            var customMetadata = new Cci.MemoryStream();
            var cmw            = new Cci.BinaryWriter(customMetadata);

            new EditAndContinueMethodDebugInformation(0x7b, slots, closures, lambdas).SerializeLambdaMap(cmw);

            var bytes = customMetadata.ToImmutableArray();

            AssertEx.Equal(new byte[] { 0x7C, 0x80, 0xC8, 0x03, 0x64, 0x80, 0xD2, 0x00, 0x80, 0xDC, 0x02, 0x80, 0x96, 0x01, 0x14, 0x00 }, bytes);

            var deserialized = EditAndContinueMethodDebugInformation.Create(default(ImmutableArray <byte>), bytes);

            AssertEx.Equal(closures, deserialized.Closures);
            AssertEx.Equal(lambdas, deserialized.Lambdas);
        }
Example #5
0
        public void EditAndContinueLambdaAndClosureMap_NegativeSyntaxOffsets()
        {
            var slots = ImmutableArray <LocalSlotDebugInfo> .Empty;

            var closures = ImmutableArray.Create(
                new ClosureDebugInfo(-100, new DebugId(0, 0)),
                new ClosureDebugInfo(10, new DebugId(1, 0)),
                new ClosureDebugInfo(-200, new DebugId(2, 0)));

            var lambdas = ImmutableArray.Create(
                new LambdaDebugInfo(20, new DebugId(0, 0), 1),
                new LambdaDebugInfo(-50, new DebugId(1, 0), 0),
                new LambdaDebugInfo(-180, new DebugId(2, 0), LambdaDebugInfo.StaticClosureOrdinal));

            var cmw = new BlobBuilder();

            new EditAndContinueMethodDebugInformation(0x7b, slots, closures, lambdas).SerializeLambdaMap(cmw);

            var bytes = cmw.ToImmutableArray();

            AssertEx.Equal(new byte[] { 0x7C, 0x80, 0xC8, 0x03, 0x64, 0x80, 0xD2, 0x00, 0x80, 0xDC, 0x03, 0x80, 0x96, 0x02, 0x14, 0x01 }, bytes);

            var deserialized = EditAndContinueMethodDebugInformation.Create(default(ImmutableArray <byte>), bytes);

            AssertEx.Equal(closures, deserialized.Closures);
            AssertEx.Equal(lambdas, deserialized.Lambdas);
        }
Example #6
0
        public static EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(byte[] customDebugInfoBlob)
        {
            var localSlots = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBlob, CustomDebugInfoKind.EditAndContinueLocalSlotMap);
            var lambdaMap  = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBlob, CustomDebugInfoKind.EditAndContinueLambdaMap);

            return(EditAndContinueMethodDebugInformation.Create(localSlots, lambdaMap));
        }
Example #7
0
        public void EditAndContinueLambdaAndClosureMap_NoLambdas()
        {
            // should not happen in practice, but EditAndContinueMethodDebugInformation should handle it just fine

            var slots    = ImmutableArray <LocalSlotDebugInfo> .Empty;
            var closures = ImmutableArray <ClosureDebugInfo> .Empty;
            var lambdas  = ImmutableArray <LambdaDebugInfo> .Empty;

            var cmw = new BlobBuilder();

            new EditAndContinueMethodDebugInformation(
                10,
                slots,
                closures,
                lambdas
                ).SerializeLambdaMap(cmw);

            var bytes = cmw.ToImmutableArray();

            AssertEx.Equal(new byte[] { 0x0B, 0x01, 0x00 }, bytes);

            var deserialized = EditAndContinueMethodDebugInformation.Create(
                default(ImmutableArray <byte>),
                bytes
                );

            AssertEx.Equal(closures, deserialized.Closures);
            AssertEx.Equal(lambdas, deserialized.Lambdas);
        }
Example #8
0
        public void EditAndContinueLambdaAndClosureMap_NoClosures()
        {
            var slots = ImmutableArray <LocalSlotDebugInfo> .Empty;

            var closures = ImmutableArray <ClosureDebugInfo> .Empty;
            var lambdas  = ImmutableArray.Create(
                new LambdaDebugInfo(20, new DebugId(0, 0), LambdaDebugInfo.StaticClosureOrdinal)
                );

            var cmw = new BlobBuilder();

            new EditAndContinueMethodDebugInformation(
                -1,
                slots,
                closures,
                lambdas
                ).SerializeLambdaMap(cmw);

            var bytes = cmw.ToImmutableArray();

            AssertEx.Equal(new byte[] { 0x00, 0x01, 0x00, 0x15, 0x01 }, bytes);

            var deserialized = EditAndContinueMethodDebugInformation.Create(
                default(ImmutableArray <byte>),
                bytes
                );

            AssertEx.Equal(closures, deserialized.Closures);
            AssertEx.Equal(lambdas, deserialized.Lambdas);
        }
Example #9
0
 public static EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(
     byte[] customDebugInfoBlob
     )
 {
     return(EditAndContinueMethodDebugInformation.Create(
                CustomDebugInfoUtilities.GetEditAndContinueLocalSlotMapRecord(customDebugInfoBlob),
                CustomDebugInfoUtilities.GetEditAndContinueLambdaMapRecord(customDebugInfoBlob)
                ));
 }
Example #10
0
 public static IEnumerable <string> InspectClosures(
     this EditAndContinueMethodDebugInformation debugInfo
     ) =>
 debugInfo.Closures.IsDefault
         ? null
         : debugInfo.Closures.Select(
     c =>
     $"Offset={c.SyntaxOffset} Id={c.ClosureId.Generation}#{c.ClosureId.Ordinal}"
     );
Example #11
0
 public static IEnumerable <string> InspectLambdas(
     this EditAndContinueMethodDebugInformation debugInfo
     ) =>
 debugInfo.Lambdas.IsDefault
         ? null
         : debugInfo.Lambdas.Select(
     l =>
     $"Offset={l.SyntaxOffset} Id={l.LambdaId.Generation}#{l.LambdaId.Ordinal} Closure={l.ClosureOrdinal}"
     );
Example #12
0
 public static IEnumerable <string> InspectLocalSlots(
     this EditAndContinueMethodDebugInformation debugInfo
     ) =>
 debugInfo.LocalSlots.IsDefault
         ? null
         : debugInfo.LocalSlots.Select(
     s =>
     $"Offset={s.Id.SyntaxOffset} Ordinal={s.Id.Ordinal} Kind={s.SynthesizedKind}"
     );
Example #13
0
        /// <summary>
        /// Match local declarations to names to generate a map from
        /// declaration to local slot. The names are indexed by slot and the
        /// assumption is that declarations are in the same order as slots.
        /// </summary>
        private static ImmutableArray <EncLocalInfo> CreateLocalSlotMap(
            EditAndContinueMethodDebugInformation methodEncInfo,
            ImmutableArray <LocalInfo <TypeSymbol> > slotMetadata
            )
        {
            var result = new EncLocalInfo[slotMetadata.Length];

            var localSlots = methodEncInfo.LocalSlots;

            if (!localSlots.IsDefault)
            {
                // In case of corrupted PDB or metadata, these lengths might not match.
                // Let's guard against such case.
                int slotCount = Math.Min(localSlots.Length, slotMetadata.Length);

                var map = new Dictionary <EncLocalInfo, int>();

                for (int slotIndex = 0; slotIndex < slotCount; slotIndex++)
                {
                    var slot = localSlots[slotIndex];
                    if (slot.SynthesizedKind.IsLongLived())
                    {
                        var metadata = slotMetadata[slotIndex];

                        // We do not emit custom modifiers on locals so ignore the
                        // previous version of the local if it had custom modifiers.
                        if (metadata.CustomModifiers.IsDefaultOrEmpty)
                        {
                            var local = new EncLocalInfo(
                                slot,
                                (Cci.ITypeReference)metadata.Type.GetCciAdapter(),
                                metadata.Constraints,
                                metadata.SignatureOpt
                                );
                            map.Add(local, slotIndex);
                        }
                    }
                }

                foreach (var pair in map)
                {
                    result[pair.Value] = pair.Key;
                }
            }

            // Populate any remaining locals that were not matched to source.
            for (int i = 0; i < result.Length; i++)
            {
                if (result[i].IsDefault)
                {
                    result[i] = new EncLocalInfo(slotMetadata[i].SignatureOpt);
                }
            }

            return(ImmutableArray.Create(result));
        }
Example #14
0
        public static EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(this ISymUnmanagedReader3 symReader, MethodDefinitionHandle handle)
        {
            var cdi = CustomDebugInfoUtilities.GetCustomDebugInfoBytes(symReader, handle, methodVersion: 1);

            if (cdi == null)
            {
                return(EditAndContinueMethodDebugInformation.Create(default(ImmutableArray <byte>), default(ImmutableArray <byte>)));
            }

            return(GetEncMethodDebugInfo(cdi));
        }
        // internal for testing
        internal static void SerializeCustomDebugInformation(EditAndContinueMethodDebugInformation debugInfo, ArrayBuilder <BlobBuilder> customDebugInfo)
        {
            if (!debugInfo.LocalSlots.IsDefaultOrEmpty)
            {
                customDebugInfo.Add(SerializeRecord(CDI.CdiKindEditAndContinueLocalSlotMap, debugInfo.SerializeLocalSlots));
            }

            if (!debugInfo.Lambdas.IsDefaultOrEmpty)
            {
                customDebugInfo.Add(SerializeRecord(CDI.CdiKindEditAndContinueLambdaMap, debugInfo.SerializeLambdaMap));
            }
        }
Example #16
0
        public void EditAndContinueLocalSlotMap_NegativeSyntaxOffsets()
        {
            var slots = ImmutableArray.Create(
                new LocalSlotDebugInfo(SynthesizedLocalKind.UserDefined, new LocalDebugId(-1, 10)),
                new LocalSlotDebugInfo(
                    SynthesizedLocalKind.TryAwaitPendingCaughtException,
                    new LocalDebugId(-20000, 10)
                    )
                );

            var closures = ImmutableArray <ClosureDebugInfo> .Empty;
            var lambdas  = ImmutableArray <LambdaDebugInfo> .Empty;

            var cmw = new BlobBuilder();

            new EditAndContinueMethodDebugInformation(
                123,
                slots,
                closures,
                lambdas
                ).SerializeLocalSlots(cmw);

            var bytes = cmw.ToImmutableArray();

            AssertEx.Equal(
                new byte[]
            {
                0xFF,
                0xC0,
                0x00,
                0x4E,
                0x20,
                0x81,
                0xC0,
                0x00,
                0x4E,
                0x1F,
                0x0A,
                0x9A,
                0x00,
                0x0A
            },
                bytes
                );

            var deserialized =
                EditAndContinueMethodDebugInformation.Create(
                    bytes,
                    default(ImmutableArray <byte>)
                    ).LocalSlots;

            AssertEx.Equal(slots, deserialized);
        }
 public override EditAndContinueMethodDebugInformation GetDebugInfo(
     MethodDefinitionHandle methodHandle
     ) =>
 EditAndContinueMethodDebugInformation.Create(
     compressedSlotMap: GetCdiBytes(
         methodHandle,
         PortableCustomDebugInfoKinds.EncLocalSlotMap
         ),
     compressedLambdaMap: GetCdiBytes(
         methodHandle,
         PortableCustomDebugInfoKinds.EncLambdaAndClosureMap
         )
     );
Example #18
0
        protected override ImmutableArray <EncLocalInfo> GetLocalSlotMapFromMetadata(
            StandaloneSignatureHandle handle,
            EditAndContinueMethodDebugInformation debugInfo
            )
        {
            Debug.Assert(!handle.IsNil);

            var localInfos = _metadataDecoder.GetLocalsOrThrow(handle);
            var result     = CreateLocalSlotMap(debugInfo, localInfos);

            Debug.Assert(result.Length == localInfos.Length);
            return(result);
        }
            public override EditAndContinueMethodDebugInformation GetDebugInfo(
                MethodDefinitionHandle methodHandle
                )
            {
                var methodToken = MetadataTokens.GetToken(methodHandle);

                byte[] debugInfo;
                try
                {
                    debugInfo = _symReader.GetCustomDebugInfo(methodToken, _version);
                }
                catch (ArgumentOutOfRangeException)
                {
                    // Sometimes the debugger returns the HRESULT for ArgumentOutOfRangeException, rather than E_FAIL,
                    // for methods without custom debug info (https://github.com/dotnet/roslyn/issues/4138).
                    debugInfo = null;
                }
                catch (Exception e) when(FatalError.ReportAndCatch(e))  // likely a bug in the compiler/debugger
                {
                    throw new InvalidDataException(e.Message, e);
                }

                try
                {
                    ImmutableArray <byte> localSlots,
                                          lambdaMap;
                    if (debugInfo != null)
                    {
                        localSlots = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(
                            debugInfo,
                            CustomDebugInfoKind.EditAndContinueLocalSlotMap
                            );
                        lambdaMap = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(
                            debugInfo,
                            CustomDebugInfoKind.EditAndContinueLambdaMap
                            );
                    }
                    else
                    {
                        localSlots = lambdaMap = default;
                    }

                    return(EditAndContinueMethodDebugInformation.Create(localSlots, lambdaMap));
                }
                catch (InvalidOperationException e) when(FatalError.ReportAndCatch(e))  // likely a bug in the compiler/debugger
                {
                    // TODO: CustomDebugInfoReader should throw InvalidDataException
                    throw new InvalidDataException(e.Message, e);
                }
            }
        public void EditAndContinueLocalSlotMap_NegativeSyntaxOffsets()
        {
            var slots = ImmutableArray.Create(
                new LocalSlotDebugInfo(SynthesizedLocalKind.UserDefined, new LocalDebugId(-1, 10)),
                new LocalSlotDebugInfo(SynthesizedLocalKind.TryAwaitPendingCaughtException, new LocalDebugId(-20000, 10)));

            var customMetadata = new Cci.MemoryStream();
            var cmw            = new Cci.BinaryWriter(customMetadata);

            new EditAndContinueMethodDebugInformation(slots).SerializeLocalSlots(cmw);

            var bytes = customMetadata.ToImmutableArray();

            AssertEx.Equal(new byte[] { 0xFE, 0xC0, 0x00, 0x4E, 0x20, 0x81, 0xC0, 0x00, 0x4E, 0x1F, 0x0A, 0x9A, 0x00, 0x0A }, bytes);

            var deserialized = EditAndContinueMethodDebugInformation.Create(bytes).LocalSlots;

            AssertEx.Equal(slots, deserialized);
        }
Example #21
0
        public void UncompressSlotMap1()
        {
            using (new EnsureEnglishUICulture())
            {
                var e = Assert.Throws <InvalidDataException>(() => EditAndContinueMethodDebugInformation.Create(ImmutableArray.Create(new byte[] { 0x01, 0x68, 0xff }), ImmutableArray <byte> .Empty));
                Assert.Equal("Invalid data at offset 3: 01-68-FF*", e.Message);

                e = Assert.Throws <InvalidDataException>(() => EditAndContinueMethodDebugInformation.Create(ImmutableArray.Create(new byte[] { 0x01, 0x68, 0xff, 0xff, 0xff, 0xff }), ImmutableArray <byte> .Empty));
                Assert.Equal("Invalid data at offset 3: 01-68-FF*FF-FF-FF", e.Message);

                e = Assert.Throws <InvalidDataException>(() => EditAndContinueMethodDebugInformation.Create(ImmutableArray.Create(new byte[] { 0xff, 0xff, 0xff, 0xff }), ImmutableArray <byte> .Empty));
                Assert.Equal("Invalid data at offset 1: FF*FF-FF-FF", e.Message);

                byte[] largeData = new byte[10000];
                largeData[400] = 0xff;
                largeData[401] = 0xff;
                largeData[402] = 0xff;
                largeData[403] = 0xff;
                largeData[404] = 0xff;
                largeData[405] = 0xff;

                e = Assert.Throws <InvalidDataException>(() => EditAndContinueMethodDebugInformation.Create(ImmutableArray.Create(largeData), ImmutableArray <byte> .Empty));
                Assert.Equal(
                    "Invalid data at offset 401: 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-FF*FF-FF-FF-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-" +
                    "00-00-00-00-00-00-00-00-00-00-00...", e.Message);
            }
        }
        public void EditAndContinueLambdaAndClosureMap_NoClosures()
        {
            var slots = ImmutableArray <LocalSlotDebugInfo> .Empty;

            var closures = ImmutableArray <ClosureDebugInfo> .Empty;
            var lambdas  = ImmutableArray.Create(new LambdaDebugInfo(20, LambdaDebugInfo.StaticClosureOrdinal));

            var customMetadata = new Cci.MemoryStream();
            var cmw            = new Cci.BinaryWriter(customMetadata);

            new EditAndContinueMethodDebugInformation(-1, slots, closures, lambdas).SerializeLambdaMap(cmw);

            var bytes = customMetadata.ToImmutableArray();

            AssertEx.Equal(new byte[] { 0x00, 0x01, 0x00, 0x15, 0x01 }, bytes);

            var deserialized = EditAndContinueMethodDebugInformation.Create(default(ImmutableArray <byte>), bytes);

            AssertEx.Equal(closures, deserialized.Closures);
            AssertEx.Equal(lambdas, deserialized.Lambdas);
        }
Example #23
0
        // internal for testing
        internal static void SerializeCustomDebugInformation(EditAndContinueMethodDebugInformation debugInfo, ArrayBuilder <PooledBlobBuilder> customDebugInfo)
        {
            // PERF: note that we pass debugInfo as explicit parameter
            //       that is intentional to avoid capturing debugInfo as that
            //       would result in a lot of delegate allocations here that are otherwise can be avoided.
            if (!debugInfo.LocalSlots.IsDefaultOrEmpty)
            {
                customDebugInfo.Add(
                    SerializeRecord(
                        CDI.CdiKindEditAndContinueLocalSlotMap,
                        debugInfo,
                        (info, builder) => info.SerializeLocalSlots(builder)));
            }

            if (!debugInfo.Lambdas.IsDefaultOrEmpty)
            {
                customDebugInfo.Add(
                    SerializeRecord(
                        CDI.CdiKindEditAndContinueLambdaMap,
                        debugInfo,
                        (info, builder) => info.SerializeLambdaMap(builder)));
            }
        }
Example #24
0
        public void EncCdiAlignment()
        {
            var slots = ImmutableArray.Create(
                new LocalSlotDebugInfo(SynthesizedLocalKind.UserDefined, new LocalDebugId(-1, 10)),
                new LocalSlotDebugInfo(SynthesizedLocalKind.TryAwaitPendingCaughtException, new LocalDebugId(-20000, 10)));

            var closures = ImmutableArray.Create(
                new ClosureDebugInfo(-100, new DebugId(0, 0)),
                new ClosureDebugInfo(10, new DebugId(1, 0)),
                new ClosureDebugInfo(-200, new DebugId(2, 0)));

            var lambdas = ImmutableArray.Create(
                new LambdaDebugInfo(20, new DebugId(0, 0), 1),
                new LambdaDebugInfo(-50, new DebugId(1, 0), 0),
                new LambdaDebugInfo(-180, new DebugId(2, 0), LambdaDebugInfo.StaticClosureOrdinal));

            var debugInfo = new EditAndContinueMethodDebugInformation(1, slots, closures, lambdas);
            var records   = new ArrayBuilder <Cci.PooledBlobBuilder>();

            Cci.CustomDebugInfoWriter.SerializeCustomDebugInformation(debugInfo, records);
            var cdi = Cci.CustomDebugInfoWriter.SerializeCustomDebugMetadata(records);

            Assert.Equal(2, records.Count);

            AssertEx.Equal(new byte[]
            {
                0x04, // version
                0x06, // record kind
                0x00,
                0x02, // alignment size

                // aligned record size
                0x18, 0x00, 0x00, 0x00,

                // payload (4B aligned)
                0xFF, 0xC0, 0x00, 0x4E,
                0x20, 0x81, 0xC0, 0x00,
                0x4E, 0x1F, 0x0A, 0x9A,
                0x00, 0x0A, 0x00, 0x00
            }, records[0].ToArray());

            AssertEx.Equal(new byte[]
            {
                0x04, // version
                0x07, // record kind
                0x00,
                0x00, // alignment size

                // aligned record size
                0x18, 0x00, 0x00, 0x00,

                // payload (4B aligned)
                0x02, 0x80, 0xC8, 0x03,
                0x64, 0x80, 0xD2, 0x00,
                0x80, 0xDC, 0x03, 0x80,
                0x96, 0x02, 0x14, 0x01
            }, records[1].ToArray());

            var deserialized = CustomDebugInfoReader.GetCustomDebugInfoRecords(cdi).ToArray();

            Assert.Equal(CustomDebugInfoKind.EditAndContinueLocalSlotMap, deserialized[0].Kind);
            Assert.Equal(4, deserialized[0].Version);

            Assert.Equal(new byte[]
            {
                0xFF, 0xC0, 0x00, 0x4E,
                0x20, 0x81, 0xC0, 0x00,
                0x4E, 0x1F, 0x0A, 0x9A,
                0x00, 0x0A
            }, deserialized[0].Data);

            Assert.Equal(CustomDebugInfoKind.EditAndContinueLambdaMap, deserialized[1].Kind);
            Assert.Equal(4, deserialized[1].Version);

            Assert.Equal(new byte[]
            {
                0x02, 0x80, 0xC8, 0x03,
                0x64, 0x80, 0xD2, 0x00,
                0x80, 0xDC, 0x03, 0x80,
                0x96, 0x02, 0x14, 0x01
            }, deserialized[1].Data);
        }
Example #25
0
        public byte[] SerializeMethodDebugInfo(EmitContext context, IMethodBody methodBody, int methodToken, bool emitEncInfo, bool suppressNewCustomDebugInfo, out bool emitExternNamespaces)
        {
            emitExternNamespaces = false;

            // CONSIDER: this may not be the same "first" method as in Dev10, but
            // it shouldn't matter since all methods will still forward to a method
            // containing the appropriate information.
            if (_methodBodyWithModuleInfo == null)
            {
                // This module level information could go on every method (and does in
                // the edit-and-continue case), but - as an optimization - we'll just
                // put it on the first method we happen to encounter and then put a
                // reference to the first method's token in every other method (so they
                // can find the information).
                if (context.Module.GetAssemblyReferenceAliases(context).Any())
                {
                    _methodTokenWithModuleInfo = methodToken;
                    _methodBodyWithModuleInfo  = methodBody;
                    emitExternNamespaces       = true;
                }
            }

            ArrayBuilder <PooledBlobBuilder> customDebugInfo = ArrayBuilder <PooledBlobBuilder> .GetInstance();

            SerializeIteratorClassMetadata(methodBody, customDebugInfo);

            // NOTE: This is an attempt to match Dev10's apparent behavior.  For iterator methods (i.e. the method
            // that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal
            // custom debug info (e.g. there will be no information about the usings that were in scope).
            // NOTE: There seems to be an unusual behavior in ISymUnmanagedWriter where, if all the methods in a type are
            // iterator methods, no custom debug info is emitted for any method.  Adding a single non-iterator
            // method causes the custom debug info to be produced for all methods (including the iterator methods).
            // Since we are making the same ISymUnmanagedWriter calls as Dev10, we see the same behavior (i.e. this
            // is not a regression).
            if (methodBody.StateMachineTypeName == null)
            {
                SerializeNamespaceScopeMetadata(context, methodBody, customDebugInfo);
                SerializeStateMachineLocalScopes(methodBody, customDebugInfo);
            }

            if (!suppressNewCustomDebugInfo)
            {
                SerializeDynamicLocalInfo(methodBody, customDebugInfo);
                SerializeTupleElementNames(methodBody, customDebugInfo);

                if (emitEncInfo)
                {
                    EditAndContinueMethodDebugInformation encMethodInfo = MetadataWriter.GetEncMethodDebugInfo(methodBody);
                    SerializeCustomDebugInformation(encMethodInfo, customDebugInfo);
                }
            }

            byte[] result = SerializeCustomDebugMetadata(customDebugInfo);

            foreach (PooledBlobBuilder builder in customDebugInfo)
            {
                builder.Free();
            }

            customDebugInfo.Free();

            return(result);
        }
        public byte[] SerializeMethodDebugInfo(IModule module, IMethodBody methodBody, uint methodToken, bool isEncDelta, bool suppressNewCustomDebugInfo, out bool emitExternNamespaces)
        {
            emitExternNamespaces = false;

            // CONSIDER: this may not be the same "first" method as in Dev10, but
            // it shouldn't matter since all methods will still forward to a method
            // containing the appropriate information.
            if (_methodBodyWithModuleInfo == null) //UNDONE: || edit-and-continue
            {
                // This module level information could go on every method (and does in
                // the edit-and-continue case), but - as an optimization - we'll just
                // put it on the first method we happen to encounter and then put a
                // reference to the first method's token in every other method (so they
                // can find the information).
                if (module.ExternNamespaces.Any())
                {
                    _methodTokenWithModuleInfo = methodToken;
                    _methodBodyWithModuleInfo  = methodBody;
                    emitExternNamespaces       = true;
                }
            }

            var customDebugInfo = ArrayBuilder <MemoryStream> .GetInstance();

            SerializeIteratorClassMetadata(methodBody, customDebugInfo);

            // NOTE: This is an attempt to match Dev10's apparent behavior.  For iterator methods (i.e. the method
            // that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal
            // custom debug info (e.g. there will be no information about the usings that were in scope).
            // NOTE: There seems to be an unusual behavior in ISymUnmanagedWriter where, if all the methods in a type are
            // iterator methods, no custom debug info is emitted for any method.  Adding a single non-iterator
            // method causes the custom debug info to be produced for all methods (including the iterator methods).
            // Since we are making the same ISymUnmanagedWriter calls as Dev10, we see the same behavior (i.e. this
            // is not a regression).
            if (methodBody.StateMachineTypeName == null)
            {
                SerializeNamespaceScopeMetadata(methodBody, customDebugInfo);
                SerializeStateMachineLocalScopes(methodBody, customDebugInfo);
            }

            if (!suppressNewCustomDebugInfo)
            {
                SerializeDynamicLocalInfo(methodBody, customDebugInfo);

                // delta doesn't need this information - we use information recorded by previous generation emit
                if (!isEncDelta)
                {
                    ImmutableArray <LocalSlotDebugInfo> encLocalSlots;

                    // Kickoff method of a state machine (async/iterator method) doens't have any interesting locals,
                    // so we use its EnC method debug info to store information about locals hoisted to the state machine.
                    var encSlotInfo = methodBody.StateMachineHoistedLocalSlots;
                    if (encSlotInfo.IsDefault)
                    {
                        encLocalSlots = GetLocalSlotDebugInfos(methodBody.LocalVariables);
                    }
                    else
                    {
                        encLocalSlots = GetLocalSlotDebugInfos(encSlotInfo);
                    }

                    var encMethodInfo = new EditAndContinueMethodDebugInformation(methodBody.MethodOrdinal, encLocalSlots, methodBody.ClosureDebugInfo, methodBody.LambdaDebugInfo);
                    encMethodInfo.SerializeCustomDebugInformation(customDebugInfo);
                }
            }

            byte[] result = SerializeCustomDebugMetadata(customDebugInfo);
            customDebugInfo.Free();
            return(result);
        }
Example #27
0
 public static int GetMethodOrdinal(this EditAndContinueMethodDebugInformation debugInfo)
 => debugInfo.MethodOrdinal;
Example #28
0
        protected override ImmutableArray <EncLocalInfo> TryGetLocalSlotMapFromMetadata(MethodDefinitionHandle handle, EditAndContinueMethodDebugInformation debugInfo)
        {
            ImmutableArray <LocalInfo <TypeSymbol> > slotMetadata;

            if (!_metadataDecoder.TryGetLocals(handle, out slotMetadata))
            {
                return(default(ImmutableArray <EncLocalInfo>));
            }

            var result = CreateLocalSlotMap(debugInfo, slotMetadata);

            Debug.Assert(result.Length == slotMetadata.Length);
            return(result);
        }