PdbToXml.cs 56.6 KB
Newer Older
1
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
P
Pilchie 已提交
2 3 4 5 6 7 8 9 10 11

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
12
using System.Reflection.Metadata.Decoding;
P
Pilchie 已提交
13 14 15 16
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Xml;
17 18
using Microsoft.CodeAnalysis;
using Microsoft.DiaSymReader;
T
Tomas Matousek 已提交
19
using Roslyn.Utilities;
20
using CDI = Microsoft.CodeAnalysis.CustomDebugInfoReader;
21
using CDIC = Microsoft.Cci.CustomDebugInfoConstants;
22
using ImportScope = Microsoft.CodeAnalysis.ImportScope;
P
Pilchie 已提交
23 24 25 26 27 28 29 30 31 32 33 34
using PooledStringBuilder = Microsoft.CodeAnalysis.Collections.PooledStringBuilder;

namespace Roslyn.Test.PdbUtilities
{
    /// <summary>
    /// Class to write out XML for a PDB.
    /// </summary>
    public sealed class PdbToXmlConverter
    {
        // For printing integers in a standard hex format.
        private const string IntHexFormat = "0x{0:X}";

B
beep boop 已提交
35
        private readonly MetadataReader _metadataReader;
36
        private readonly ISymUnmanagedReader _symReader;
B
beep boop 已提交
37 38
        private readonly PdbToXmlOptions _options;
        private readonly XmlWriter _writer;
P
Pilchie 已提交
39 40

        // Maps files to ids. 
B
beep boop 已提交
41
        private readonly Dictionary<string, int> _fileMapping = new Dictionary<string, int>();
P
Pilchie 已提交
42

43
        private PdbToXmlConverter(XmlWriter writer, ISymUnmanagedReader symReader, MetadataReader metadataReader, PdbToXmlOptions options)
P
Pilchie 已提交
44
        {
45
            _symReader = symReader;
B
beep boop 已提交
46 47 48
            _metadataReader = metadataReader;
            _writer = writer;
            _options = options;
P
Pilchie 已提交
49 50
        }

51
        public unsafe static string DeltaPdbToXml(Stream deltaPdb, IEnumerable<int> methodTokens)
P
Pilchie 已提交
52 53 54
        {
            var writer = new StringWriter();
            ToXml(
55 56
                writer,
                deltaPdb,
P
Pilchie 已提交
57
                metadataReaderOpt: null,
58
                options: PdbToXmlOptions.IncludeTokens,
59
                methodHandles: methodTokens.Select(token => (MethodDefinitionHandle)MetadataTokens.Handle(token)));
P
Pilchie 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

            return writer.ToString();
        }

        public static string ToXml(Stream pdbStream, Stream peStream, PdbToXmlOptions options = PdbToXmlOptions.ResolveTokens, string methodName = null)
        {
            var writer = new StringWriter();
            ToXml(writer, pdbStream, peStream, options, methodName);
            return writer.ToString();
        }

        public static string ToXml(Stream pdbStream, byte[] peImage, PdbToXmlOptions options = PdbToXmlOptions.ResolveTokens, string methodName = null)
        {
            var writer = new StringWriter();
            ToXml(writer, pdbStream, new MemoryStream(peImage), options, methodName);
            return writer.ToString();
        }

        public unsafe static void ToXml(TextWriter xmlWriter, Stream pdbStream, Stream peStream, PdbToXmlOptions options = PdbToXmlOptions.Default, string methodName = null)
        {
A
angocke 已提交
80
            IEnumerable<MethodDefinitionHandle> methodHandles;
P
Pilchie 已提交
81 82 83 84 85 86 87
            var headers = new PEHeaders(peStream);
            byte[] metadata = new byte[headers.MetadataSize];
            peStream.Seek(headers.MetadataStartOffset, SeekOrigin.Begin);
            peStream.Read(metadata, 0, headers.MetadataSize);

            fixed (byte* metadataPtr = metadata)
            {
A
angocke 已提交
88
                var metadataReader = new MetadataReader(metadataPtr, metadata.Length);
P
Pilchie 已提交
89 90 91 92 93 94 95

                if (string.IsNullOrEmpty(methodName))
                {
                    methodHandles = metadataReader.MethodDefinitions;
                }
                else
                {
96 97 98 99 100 101
                    var matching = metadataReader.MethodDefinitions.
                        Where(methodHandle => GetQualifiedMethodName(metadataReader, methodHandle) == methodName).ToArray();

                    if (matching.Length == 0)
                    {
                        xmlWriter.WriteLine("<error>");
102
                        xmlWriter.WriteLine(string.Format("<message><![CDATA[No method '{0}' found in metadata.]]></message>", methodName));
103 104 105 106 107 108 109 110
                        xmlWriter.WriteLine("<available-methods>");

                        foreach (var methodHandle in metadataReader.MethodDefinitions)
                        {
                            xmlWriter.Write("<method><![CDATA[");
                            xmlWriter.Write(GetQualifiedMethodName(metadataReader, methodHandle));
                            xmlWriter.Write("]]></method>");
                            xmlWriter.WriteLine();
111
                        }
112 113 114 115 116 117 118 119

                        xmlWriter.WriteLine("</available-methods>");
                        xmlWriter.WriteLine("</error>");

                        return;
                    }

                    methodHandles = matching;
P
Pilchie 已提交
120 121 122 123 124 125
                }

                ToXml(xmlWriter, pdbStream, metadataReader, options, methodHandles);
            }
        }

T
tmat 已提交
126 127 128 129 130 131 132 133
        private static XmlWriterSettings s_xmlWriterSettings = new XmlWriterSettings
        {
            Encoding = Encoding.UTF8,
            Indent = true,
            IndentChars = "  ",
            NewLineChars = "\r\n",
        };

P
Pilchie 已提交
134 135 136 137
        /// <summary>
        /// Load the PDB given the parameters at the ctor and spew it out to the XmlWriter specified
        /// at the ctor.
        /// </summary>
A
angocke 已提交
138
        private static void ToXml(TextWriter xmlWriter, Stream pdbStream, MetadataReader metadataReaderOpt, PdbToXmlOptions options, IEnumerable<MethodDefinitionHandle> methodHandles)
P
Pilchie 已提交
139 140 141 142
        {
            Debug.Assert(pdbStream != null);
            Debug.Assert((options & PdbToXmlOptions.ResolveTokens) == 0 || metadataReaderOpt != null);

T
tmat 已提交
143
            using (var writer = XmlWriter.Create(xmlWriter, s_xmlWriterSettings))
P
Pilchie 已提交
144
            {
T
tmat 已提交
145 146 147
                using (SymReader symReader = new SymReader(pdbStream, metadataReaderOpt))
                {
                    var converter = new PdbToXmlConverter(writer, symReader, metadataReaderOpt, options);
P
Pilchie 已提交
148

T
tmat 已提交
149 150
                    converter.WriteRoot(methodHandles ?? metadataReaderOpt.MethodDefinitions);
                }
P
Pilchie 已提交
151 152 153
            }
        }

A
angocke 已提交
154
        private void WriteRoot(IEnumerable<MethodDefinitionHandle> methodHandles)
P
Pilchie 已提交
155
        {
B
beep boop 已提交
156
            _writer.WriteStartDocument();
P
Pilchie 已提交
157

B
beep boop 已提交
158
            _writer.WriteStartElement("symbols");
P
Pilchie 已提交
159 160 161 162 163

            WriteDocList();
            WriteEntryPoint();
            WriteAllMethods(methodHandles);

B
beep boop 已提交
164
            if ((_options & PdbToXmlOptions.IncludeMethodSpans) != 0)
P
Pilchie 已提交
165 166 167 168
            {
                WriteAllMethodSpans();
            }

B
beep boop 已提交
169
            _writer.WriteEndElement();
P
Pilchie 已提交
170 171 172
        }

        // Dump all of the methods in the given ISymbolReader to the XmlWriter provided in the ctor.
A
angocke 已提交
173
        private void WriteAllMethods(IEnumerable<MethodDefinitionHandle> methodHandles)
P
Pilchie 已提交
174
        {
B
beep boop 已提交
175
            _writer.WriteStartElement("methods");
P
Pilchie 已提交
176 177 178 179 180 181

            foreach (var methodHandle in methodHandles)
            {
                WriteMethod(methodHandle);
            }

B
beep boop 已提交
182
            _writer.WriteEndElement();
P
Pilchie 已提交
183 184
        }

A
angocke 已提交
185
        private void WriteMethod(MethodDefinitionHandle methodHandle)
P
Pilchie 已提交
186
        {
B
beep boop 已提交
187
            int token = _metadataReader.GetToken(methodHandle);
P
Pilchie 已提交
188

189 190
            byte[] cdi = _symReader.GetCustomDebugInfoBytes(token, methodVersion: 1);
            ISymUnmanagedMethod method = _symReader.GetMethod(token);
191
            if (cdi == null && method == null)
P
Pilchie 已提交
192 193 194 195 196
            {
                // no debug info for the method
                return;
            }

B
beep boop 已提交
197
            _writer.WriteStartElement("method");
P
Pilchie 已提交
198 199
            WriteMethodAttributes(token, isReference: false);

200
            if (cdi != null)
P
Pilchie 已提交
201
            {
202
                WriteCustomDebugInfo(cdi);
P
Pilchie 已提交
203 204
            }

205
            if (method != null)
P
Pilchie 已提交
206
            {
207
                WriteSequencePoints(method);
P
Pilchie 已提交
208

209
                var rootScope = method.GetRootScope();
P
Pilchie 已提交
210

211
                // The root scope is always empty. The first scope opened by SymWriter is the child of the root scope.
212
                if (rootScope.GetNamespaces().IsEmpty && rootScope.GetLocals().IsEmpty && rootScope.GetConstants().IsEmpty)
P
Pilchie 已提交
213
                {
214
                    foreach (ISymUnmanagedScope child in rootScope.GetScopes())
P
Pilchie 已提交
215
                    {
216
                        WriteScope(child, isRoot: false);
P
Pilchie 已提交
217 218
                    }
                }
219
                else
P
Pilchie 已提交
220
                {
221
                    // This shouldn't be executed for PDBs generated via SymWriter.
222
                    WriteScope(rootScope, isRoot: true);
P
Pilchie 已提交
223 224
                }

225
                WriteAsyncInfo(method);
P
Pilchie 已提交
226 227
            }

B
beep boop 已提交
228
            _writer.WriteEndElement(); // method
P
Pilchie 已提交
229 230 231 232 233 234 235 236
        }

        /// <summary>
        /// Given a byte array of custom debug info, parse the array and write out XML describing
        /// its structure and contents.
        /// </summary>
        private void WriteCustomDebugInfo(byte[] bytes)
        {
237
            var records = CustomDebugInfoReader.GetCustomDebugInfoRecords(bytes).ToArray();
238

B
beep boop 已提交
239
            _writer.WriteStartElement("customDebugInfo");
P
Pilchie 已提交
240

241
            foreach (var record in records)
P
Pilchie 已提交
242
            {
243
                if (record.Version != CDIC.CdiVersion)
P
Pilchie 已提交
244
                {
245
                    WriteUnknownCustomDebugInfo(record);
P
Pilchie 已提交
246 247 248
                }
                else
                {
249
                    switch (record.Kind)
P
Pilchie 已提交
250 251
                    {
                        case CustomDebugInfoKind.UsingInfo:
252
                            WriteUsingCustomDebugInfo(record);
P
Pilchie 已提交
253 254
                            break;
                        case CustomDebugInfoKind.ForwardInfo:
255
                            WriteForwardCustomDebugInfo(record);
P
Pilchie 已提交
256 257
                            break;
                        case CustomDebugInfoKind.ForwardToModuleInfo:
258
                            WriteForwardToModuleCustomDebugInfo(record);
P
Pilchie 已提交
259
                            break;
260
                        case CustomDebugInfoKind.StateMachineHoistedLocalScopes:
261
                            WriteStatemachineHoistedLocalScopesCustomDebugInfo(record);
P
Pilchie 已提交
262 263
                            break;
                        case CustomDebugInfoKind.ForwardIterator:
264
                            WriteForwardIteratorCustomDebugInfo(record);
P
Pilchie 已提交
265 266
                            break;
                        case CustomDebugInfoKind.DynamicLocals:
267
                            WriteDynamicLocalsCustomDebugInfo(record);
P
Pilchie 已提交
268
                            break;
269
                        case CustomDebugInfoKind.EditAndContinueLocalSlotMap:
270
                            WriteEditAndContinueLocalSlotMap(record);
271
                            break;
272 273 274
                        case CustomDebugInfoKind.EditAndContinueLambdaMap:
                            WriteEditAndContinueLambdaMap(record);
                            break;
P
Pilchie 已提交
275
                        default:
276
                            WriteUnknownCustomDebugInfo(record);
P
Pilchie 已提交
277 278 279 280 281
                            break;
                    }
                }
            }

B
beep boop 已提交
282
            _writer.WriteEndElement(); //customDebugInfo
P
Pilchie 已提交
283 284 285 286 287 288 289
        }

        /// <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>
290
        private void WriteUnknownCustomDebugInfo(CustomDebugInfoRecord record)
P
Pilchie 已提交
291
        {
B
beep boop 已提交
292 293
            _writer.WriteStartElement("unknown");
            _writer.WriteAttributeString("kind", record.Kind.ToString());
T
Tomas Matousek 已提交
294
            _writer.WriteAttributeString("version", CultureInvariantToString(record.Version));
P
Pilchie 已提交
295 296 297

            PooledStringBuilder pooled = PooledStringBuilder.GetInstance();
            StringBuilder builder = pooled.Builder;
298
            foreach (byte b in record.Data)
P
Pilchie 已提交
299 300 301
            {
                builder.AppendFormat("{0:X2}", b);
            }
302

B
beep boop 已提交
303
            _writer.WriteAttributeString("payload", pooled.ToStringAndFree());
P
Pilchie 已提交
304

B
beep boop 已提交
305
            _writer.WriteEndElement(); //unknown
P
Pilchie 已提交
306 307 308 309 310 311 312 313 314
        }

        /// <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>
315
        private void WriteUsingCustomDebugInfo(CustomDebugInfoRecord record)
P
Pilchie 已提交
316
        {
317
            Debug.Assert(record.Kind == CustomDebugInfoKind.UsingInfo);
P
Pilchie 已提交
318

B
beep boop 已提交
319
            _writer.WriteStartElement("using");
P
Pilchie 已提交
320

321
            ImmutableArray<short> counts = CDI.DecodeUsingRecord(record.Data);
P
Pilchie 已提交
322 323 324

            foreach (short importCount in counts)
            {
B
beep boop 已提交
325
                _writer.WriteStartElement("namespace");
T
Tomas Matousek 已提交
326
                _writer.WriteAttributeString("usingCount", CultureInvariantToString(importCount));
B
beep boop 已提交
327
                _writer.WriteEndElement(); //namespace
P
Pilchie 已提交
328 329
            }

B
beep boop 已提交
330
            _writer.WriteEndElement(); //using
P
Pilchie 已提交
331 332 333 334 335 336 337 338 339
        }

        /// <summary>
        /// This indicates that further information can be obtained by looking at the custom debug
        /// info of another method (specified by token).
        /// </summary>
        /// <remarks>
        /// Emitting tokens makes tests more fragile.
        /// </remarks>
340
        private void WriteForwardCustomDebugInfo(CustomDebugInfoRecord record)
P
Pilchie 已提交
341
        {
342
            Debug.Assert(record.Kind == CustomDebugInfoKind.ForwardInfo);
P
Pilchie 已提交
343

B
beep boop 已提交
344
            _writer.WriteStartElement("forward");
P
Pilchie 已提交
345

346
            int token = CDI.DecodeForwardRecord(record.Data);
P
Pilchie 已提交
347 348
            WriteMethodAttributes(token, isReference: true);

B
beep boop 已提交
349
            _writer.WriteEndElement(); //forward
P
Pilchie 已提交
350 351 352 353 354 355 356 357 358 359
        }

        /// <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>
360
        private void WriteForwardToModuleCustomDebugInfo(CustomDebugInfoRecord record)
P
Pilchie 已提交
361
        {
362
            Debug.Assert(record.Kind == CustomDebugInfoKind.ForwardToModuleInfo);
P
Pilchie 已提交
363

B
beep boop 已提交
364
            _writer.WriteStartElement("forwardToModule");
P
Pilchie 已提交
365

366
            int token = CDI.DecodeForwardRecord(record.Data);
P
Pilchie 已提交
367 368
            WriteMethodAttributes(token, isReference: true);

B
beep boop 已提交
369
            _writer.WriteEndElement(); //forwardToModule
P
Pilchie 已提交
370 371 372 373 374 375 376 377 378 379
        }

        /// <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>
380
        private void WriteStatemachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoRecord record)
P
Pilchie 已提交
381
        {
382
            Debug.Assert(record.Kind == CustomDebugInfoKind.StateMachineHoistedLocalScopes);
P
Pilchie 已提交
383

B
beep boop 已提交
384
            _writer.WriteStartElement("hoistedLocalScopes");
P
Pilchie 已提交
385

386
            var scopes = CDI.DecodeStateMachineHoistedLocalScopesRecord(record.Data);
P
Pilchie 已提交
387

388
            foreach (StateMachineHoistedLocalScope scope in scopes)
P
Pilchie 已提交
389
            {
B
beep boop 已提交
390 391 392 393
                _writer.WriteStartElement("slot");
                _writer.WriteAttributeString("startOffset", AsILOffset(scope.StartOffset));
                _writer.WriteAttributeString("endOffset", AsILOffset(scope.EndOffset));
                _writer.WriteEndElement(); //bucket
P
Pilchie 已提交
394 395
            }

B
beep boop 已提交
396
            _writer.WriteEndElement();
P
Pilchie 已提交
397 398 399 400 401 402 403 404 405
        }

        /// <summary>
        /// Contains a name string.
        /// TODO: comment when the structure is understood.
        /// </summary>
        /// <remarks>
        /// Appears when are iterator methods.
        /// </remarks>
406
        private void WriteForwardIteratorCustomDebugInfo(CustomDebugInfoRecord record)
P
Pilchie 已提交
407
        {
408
            Debug.Assert(record.Kind == CustomDebugInfoKind.ForwardIterator);
P
Pilchie 已提交
409

B
beep boop 已提交
410
            _writer.WriteStartElement("forwardIterator");
P
Pilchie 已提交
411

412
            string name = CDI.DecodeForwardIteratorRecord(record.Data);
P
Pilchie 已提交
413

B
beep boop 已提交
414
            _writer.WriteAttributeString("name", name);
P
Pilchie 已提交
415

B
beep boop 已提交
416
            _writer.WriteEndElement(); //forwardIterator
P
Pilchie 已提交
417 418 419 420 421 422 423 424 425
        }

        /// <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>
426
        private void WriteDynamicLocalsCustomDebugInfo(CustomDebugInfoRecord record)
P
Pilchie 已提交
427
        {
428
            Debug.Assert(record.Kind == CustomDebugInfoKind.DynamicLocals);
P
Pilchie 已提交
429

B
beep boop 已提交
430
            _writer.WriteStartElement("dynamicLocals");
P
Pilchie 已提交
431

432
            var buckets = CDI.DecodeDynamicLocalsRecord(record.Data);
P
Pilchie 已提交
433 434 435 436 437 438 439 440 441 442 443 444 445

            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);
                }

B
beep boop 已提交
446
                _writer.WriteStartElement("bucket");
T
Tomas Matousek 已提交
447
                _writer.WriteAttributeString("flagCount", CultureInvariantToString(flagCount));
B
beep boop 已提交
448
                _writer.WriteAttributeString("flags", pooled.ToStringAndFree());
T
Tomas Matousek 已提交
449
                _writer.WriteAttributeString("slotId", CultureInvariantToString(bucket.SlotId));
B
beep boop 已提交
450 451
                _writer.WriteAttributeString("localName", bucket.Name);
                _writer.WriteEndElement(); //bucket
P
Pilchie 已提交
452 453
            }

B
beep boop 已提交
454
            _writer.WriteEndElement(); //dynamicLocals
P
Pilchie 已提交
455 456
        }

457
        private unsafe void WriteEditAndContinueLocalSlotMap(CustomDebugInfoRecord record)
458
        {
459
            Debug.Assert(record.Kind == CustomDebugInfoKind.EditAndContinueLocalSlotMap);
460

B
beep boop 已提交
461
            _writer.WriteStartElement("encLocalSlotMap");
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
            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))
                            {
B
beep boop 已提交
478
                                _writer.WriteElementString("baseline", "?");
479 480 481 482 483 484
                                return;
                            }

                            syntaxOffsetBaseline = -syntaxOffsetBaseline;
                            continue;
                        }
485

B
beep boop 已提交
486
                        _writer.WriteStartElement("slot");
487 488 489 490

                        if (b == 0)
                        {
                            // short-lived temp, no info
B
beep boop 已提交
491
                            _writer.WriteAttributeString("kind", "temp");
492 493 494 495 496
                        }
                        else
                        {
                            int synthesizedKind = (b & 0x3f) - 1;
                            bool hasOrdinal = (b & (1 << 7)) != 0;
497

498 499 500 501 502 503 504
                            int syntaxOffset;
                            bool badSyntaxOffset = !blobReader.TryReadCompressedInteger(out syntaxOffset);
                            syntaxOffset += syntaxOffsetBaseline;

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

T
Tomas Matousek 已提交
505 506
                            _writer.WriteAttributeString("kind", CultureInvariantToString(synthesizedKind));
                            _writer.WriteAttributeString("offset", badSyntaxOffset ? "?" : CultureInvariantToString(syntaxOffset));
507 508 509

                            if (badOrdinal || hasOrdinal)
                            {
T
Tomas Matousek 已提交
510
                                _writer.WriteAttributeString("ordinal", badOrdinal ? "?" : CultureInvariantToString(ordinal));
511 512 513
                            }
                        }

B
beep boop 已提交
514
                        _writer.WriteEndElement();
515 516 517 518
                    }
                }
            }
            finally
519
            {
B
beep boop 已提交
520
                _writer.WriteEndElement(); //encLocalSlotMap
521 522 523 524 525 526
            }
        }

        private unsafe void WriteEditAndContinueLambdaMap(CustomDebugInfoRecord record)
        {
            Debug.Assert(record.Kind == CustomDebugInfoKind.EditAndContinueLambdaMap);
527

B
beep boop 已提交
528
            _writer.WriteStartElement("encLambdaMap");
529 530 531
            try
            {
                if (record.Data.Length == 0)
532
                {
533 534
                    return;
                }
535

536 537 538 539 540 541 542 543 544
                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))
545
                    {
B
beep boop 已提交
546 547
                        _writer.WriteElementString("methodOrdinal", "?");
                        _writer.WriteEndElement();
548
                        return;
549 550
                    }

551 552
                    // [-1, inf)
                    methodOrdinal--;
T
Tomas Matousek 已提交
553
                    _writer.WriteElementString("methodOrdinal", CultureInvariantToString(methodOrdinal));
554 555

                    if (!blobReader.TryReadCompressedInteger(out syntaxOffsetBaseline))
556
                    {
B
beep boop 已提交
557 558
                        _writer.WriteElementString("baseline", "?");
                        _writer.WriteEndElement();
559
                        return;
560 561
                    }

562 563
                    syntaxOffsetBaseline = -syntaxOffsetBaseline;
                    if (!blobReader.TryReadCompressedInteger(out closureCount))
564
                    {
B
beep boop 已提交
565 566
                        _writer.WriteElementString("closureCount", "?");
                        _writer.WriteEndElement();
567
                        return;
568
                    }
569 570

                    for (int i = 0; i < closureCount; i++)
571
                    {
B
beep boop 已提交
572
                        _writer.WriteStartElement("closure");
573 574 575 576 577
                        try
                        {
                            int syntaxOffset;
                            if (!blobReader.TryReadCompressedInteger(out syntaxOffset))
                            {
B
beep boop 已提交
578
                                _writer.WriteElementString("offset", "?");
579 580 581
                                break;
                            }

T
Tomas Matousek 已提交
582
                            _writer.WriteAttributeString("offset", CultureInvariantToString(syntaxOffset + syntaxOffsetBaseline));
583 584 585
                        }
                        finally
                        {
B
beep boop 已提交
586
                            _writer.WriteEndElement();
587 588
                        }
                    }
589

590 591
                    while (blobReader.RemainingBytes > 0)
                    {
B
beep boop 已提交
592
                        _writer.WriteStartElement("lambda");
593 594 595 596 597
                        try
                        {
                            int syntaxOffset;
                            if (!blobReader.TryReadCompressedInteger(out syntaxOffset))
                            {
B
beep boop 已提交
598
                                _writer.WriteElementString("offset", "?");
599 600
                                return;
                            }
601

T
Tomas Matousek 已提交
602
                            _writer.WriteAttributeString("offset", CultureInvariantToString(syntaxOffset + syntaxOffsetBaseline));
603

604 605 606
                            int closureOrdinal;
                            if (!blobReader.TryReadCompressedInteger(out closureOrdinal))
                            {
B
beep boop 已提交
607
                                _writer.WriteElementString("closure", "?");
608 609
                                return;
                            }
610

611 612 613 614 615 616 617
                            closureOrdinal -= 2;

                            if (closureOrdinal == -2)
                            {
                                _writer.WriteAttributeString("closure", "this");
                            }
                            else if (closureOrdinal != -1)
618
                            {
B
beep boop 已提交
619
                                _writer.WriteAttributeString("closure",
T
Tomas Matousek 已提交
620
                                    CultureInvariantToString(closureOrdinal) + (closureOrdinal >= closureCount ? " (invalid)" : ""));
621 622 623
                            }
                        }
                        finally
624
                        {
B
beep boop 已提交
625
                            _writer.WriteEndElement();
626 627 628 629
                        }
                    }
                }
            }
630 631
            finally
            {
B
beep boop 已提交
632
                _writer.WriteEndElement(); //encLocalSlotMap
633
            }
634 635
        }

636
        private void WriteScope(ISymUnmanagedScope scope, bool isRoot)
P
Pilchie 已提交
637
        {
638 639 640 641 642
            _writer.WriteStartElement(isRoot ? "rootScope" : "scope");
            _writer.WriteAttributeString("startOffset", AsILOffset(scope.GetStartOffset()));
            _writer.WriteAttributeString("endOffset", AsILOffset(scope.GetEndOffset()));

            foreach (ISymUnmanagedNamespace @namespace in scope.GetNamespaces())
P
Pilchie 已提交
643
            {
644 645
                WriteNamespace(@namespace);
            }
P
Pilchie 已提交
646

647 648 649 650 651
            WriteLocals(scope);

            foreach (ISymUnmanagedScope child in scope.GetScopes())
            {
                WriteScope(child, isRoot: false);
P
Pilchie 已提交
652
            }
653

J
Jared Parsons 已提交
654
            _writer.WriteEndElement();
P
Pilchie 已提交
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
        }

        private void WriteNamespace(ISymUnmanagedNamespace @namespace)
        {
            string rawName = @namespace.GetName();

            string alias;
            string externAlias;
            string target;
            ImportTargetKind kind;
            ImportScope scope;

            try
            {
                if (rawName.Length == 0)
                {
                    externAlias = null;
672 673
                    var parsingSucceeded = CDI.TryParseVisualBasicImportString(rawName, out alias, out target, out kind, out scope);
                    Debug.Assert(parsingSucceeded);
P
Pilchie 已提交
674 675 676 677 678 679 680 681 682 683
                }
                else
                {
                    switch (rawName[0])
                    {
                        case 'U':
                        case 'A':
                        case 'X':
                        case 'Z':
                        case 'E':
684
                        case 'T':
P
Pilchie 已提交
685
                            scope = ImportScope.Unspecified;
686 687 688 689
                            if (!CDI.TryParseCSharpImportString(rawName, out alias, out externAlias, out target, out kind))
                            {
                                throw new InvalidOperationException(string.Format("Invalid import '{0}'", rawName));
                            }
P
Pilchie 已提交
690 691 692 693
                            break;

                        default:
                            externAlias = null;
694 695 696 697
                            if (!CDI.TryParseVisualBasicImportString(rawName, out alias, out target, out kind, out scope))
                            {
                                throw new InvalidOperationException(string.Format("Invalid import '{0}'", rawName));
                            }
P
Pilchie 已提交
698 699 700 701 702 703
                            break;
                    }
                }
            }
            catch (ArgumentException) // TODO: filter
            {
B
beep boop 已提交
704
                if ((_options & PdbToXmlOptions.ThrowOnError) != 0)
P
Pilchie 已提交
705 706 707 708
                {
                    throw;
                }

B
beep boop 已提交
709 710 711
                _writer.WriteStartElement("invalid-custom-data");
                _writer.WriteAttributeString("raw", rawName);
                _writer.WriteEndElement();
P
Pilchie 已提交
712 713 714 715 716 717 718 719 720
                return;
            }

            switch (kind)
            {
                case ImportTargetKind.CurrentNamespace:
                    Debug.Assert(alias == null);
                    Debug.Assert(externAlias == null);
                    Debug.Assert(scope == ImportScope.Unspecified);
B
beep boop 已提交
721 722 723
                    _writer.WriteStartElement("currentnamespace");
                    _writer.WriteAttributeString("name", target);
                    _writer.WriteEndElement(); // </currentnamespace>
P
Pilchie 已提交
724 725 726 727 728
                    break;
                case ImportTargetKind.DefaultNamespace:
                    Debug.Assert(alias == null);
                    Debug.Assert(externAlias == null);
                    Debug.Assert(scope == ImportScope.Unspecified);
B
beep boop 已提交
729 730 731
                    _writer.WriteStartElement("defaultnamespace");
                    _writer.WriteAttributeString("name", target);
                    _writer.WriteEndElement(); // </defaultnamespace>
P
Pilchie 已提交
732 733 734 735 736 737
                    break;
                case ImportTargetKind.MethodToken:
                    Debug.Assert(alias == null);
                    Debug.Assert(externAlias == null);
                    Debug.Assert(scope == ImportScope.Unspecified);
                    int token = Convert.ToInt32(target);
B
beep boop 已提交
738
                    _writer.WriteStartElement("importsforward");
P
Pilchie 已提交
739
                    WriteMethodAttributes(token, isReference: true);
B
beep boop 已提交
740
                    _writer.WriteEndElement(); // </importsforward>
P
Pilchie 已提交
741 742 743
                    break;
                case ImportTargetKind.XmlNamespace:
                    Debug.Assert(externAlias == null);
B
beep boop 已提交
744 745 746
                    _writer.WriteStartElement("xmlnamespace");
                    _writer.WriteAttributeString("prefix", alias);
                    _writer.WriteAttributeString("name", target);
P
Pilchie 已提交
747
                    WriteScopeAttribute(scope);
B
beep boop 已提交
748
                    _writer.WriteEndElement(); // </xmlnamespace>
P
Pilchie 已提交
749 750 751
                    break;
                case ImportTargetKind.NamespaceOrType:
                    Debug.Assert(externAlias == null);
B
beep boop 已提交
752 753 754 755
                    _writer.WriteStartElement("alias");
                    _writer.WriteAttributeString("name", alias);
                    _writer.WriteAttributeString("target", target);
                    _writer.WriteAttributeString("kind", "namespace"); // Strange, but retaining to avoid breaking tests.
P
Pilchie 已提交
756
                    WriteScopeAttribute(scope);
B
beep boop 已提交
757
                    _writer.WriteEndElement(); // </alias>
P
Pilchie 已提交
758 759 760 761
                    break;
                case ImportTargetKind.Namespace:
                    if (alias != null)
                    {
B
beep boop 已提交
762 763 764 765 766
                        _writer.WriteStartElement("alias");
                        _writer.WriteAttributeString("name", alias);
                        if (externAlias != null) _writer.WriteAttributeString("qualifier", externAlias);
                        _writer.WriteAttributeString("target", target);
                        _writer.WriteAttributeString("kind", "namespace");
P
Pilchie 已提交
767
                        Debug.Assert(scope == ImportScope.Unspecified); // Only C# hits this case.
B
beep boop 已提交
768
                        _writer.WriteEndElement(); // </alias>
P
Pilchie 已提交
769 770 771
                    }
                    else
                    {
B
beep boop 已提交
772 773 774
                        _writer.WriteStartElement("namespace");
                        if (externAlias != null) _writer.WriteAttributeString("qualifier", externAlias);
                        _writer.WriteAttributeString("name", target);
P
Pilchie 已提交
775
                        WriteScopeAttribute(scope);
B
beep boop 已提交
776
                        _writer.WriteEndElement(); // </namespace>
P
Pilchie 已提交
777 778 779 780 781 782
                    }
                    break;
                case ImportTargetKind.Type:
                    Debug.Assert(externAlias == null);
                    if (alias != null)
                    {
B
beep boop 已提交
783 784 785 786
                        _writer.WriteStartElement("alias");
                        _writer.WriteAttributeString("name", alias);
                        _writer.WriteAttributeString("target", target);
                        _writer.WriteAttributeString("kind", "type");
P
Pilchie 已提交
787
                        Debug.Assert(scope == ImportScope.Unspecified); // Only C# hits this case.
B
beep boop 已提交
788
                        _writer.WriteEndElement(); // </alias>
P
Pilchie 已提交
789 790 791
                    }
                    else
                    {
B
beep boop 已提交
792 793
                        _writer.WriteStartElement("type");
                        _writer.WriteAttributeString("name", target);
P
Pilchie 已提交
794
                        WriteScopeAttribute(scope);
B
beep boop 已提交
795
                        _writer.WriteEndElement(); // </type>
P
Pilchie 已提交
796 797 798
                    }
                    break;
                case ImportTargetKind.Assembly:
799 800
                    Debug.Assert(alias != null);
                    Debug.Assert(externAlias == null);
P
Pilchie 已提交
801 802 803
                    Debug.Assert(scope == ImportScope.Unspecified);
                    if (target == null)
                    {
B
beep boop 已提交
804 805 806
                        _writer.WriteStartElement("extern");
                        _writer.WriteAttributeString("alias", alias);
                        _writer.WriteEndElement(); // </extern>
P
Pilchie 已提交
807 808 809
                    }
                    else
                    {
B
beep boop 已提交
810 811 812 813
                        _writer.WriteStartElement("externinfo");
                        _writer.WriteAttributeString("alias", alias);
                        _writer.WriteAttributeString("assembly", target);
                        _writer.WriteEndElement(); // </externinfo>
P
Pilchie 已提交
814 815
                    }
                    break;
A
acasey 已提交
816 817 818
                case ImportTargetKind.Defunct:
                    Debug.Assert(alias == null);
                    Debug.Assert(scope == ImportScope.Unspecified);
B
beep boop 已提交
819 820 821
                    _writer.WriteStartElement("defunct");
                    _writer.WriteAttributeString("name", rawName);
                    _writer.WriteEndElement(); // </defunct>
A
acasey 已提交
822
                    break;
P
Pilchie 已提交
823 824
                default:
                    Debug.Assert(false, "Unexpected import kind '" + kind + "'");
B
beep boop 已提交
825 826 827
                    _writer.WriteStartElement("unknown");
                    _writer.WriteAttributeString("name", rawName);
                    _writer.WriteEndElement(); // </unknown>
P
Pilchie 已提交
828 829 830 831 832 833 834 835
                    break;
            }
        }

        private void WriteScopeAttribute(ImportScope scope)
        {
            if (scope == ImportScope.File)
            {
B
beep boop 已提交
836
                _writer.WriteAttributeString("importlevel", "file");
P
Pilchie 已提交
837 838 839
            }
            else if (scope == ImportScope.Project)
            {
B
beep boop 已提交
840
                _writer.WriteAttributeString("importlevel", "project");
P
Pilchie 已提交
841 842 843 844 845 846 847
            }
            else
            {
                Debug.Assert(scope == ImportScope.Unspecified, "Unexpected scope '" + scope + "'");
            }
        }

848
        private void WriteAsyncInfo(ISymUnmanagedMethod method)
P
Pilchie 已提交
849
        {
850 851
            var asyncMethod = method.AsAsync();
            if (asyncMethod == null)
P
Pilchie 已提交
852
            {
853 854
                return;
            }
855

B
beep boop 已提交
856
            _writer.WriteStartElement("asyncInfo");
P
Pilchie 已提交
857

858 859 860
            var catchOffset = asyncMethod.GetCatchHandlerILOffset();
            if (catchOffset >= 0)
            {
B
beep boop 已提交
861 862 863
                _writer.WriteStartElement("catchHandler");
                _writer.WriteAttributeString("offset", AsILOffset(catchOffset));
                _writer.WriteEndElement();
P
Pilchie 已提交
864 865
            }

B
beep boop 已提交
866
            _writer.WriteStartElement("kickoffMethod");
867
            WriteMethodAttributes(asyncMethod.GetKickoffMethod(), isReference: true);
B
beep boop 已提交
868
            _writer.WriteEndElement();
869 870

            foreach (var info in asyncMethod.GetAsyncStepInfos())
P
Pilchie 已提交
871
            {
B
beep boop 已提交
872 873 874
                _writer.WriteStartElement("await");
                _writer.WriteAttributeString("yield", AsILOffset(info.YieldOffset));
                _writer.WriteAttributeString("resume", AsILOffset(info.ResumeOffset));
875
                WriteMethodAttributes(info.ResumeMethod, isReference: true);
B
beep boop 已提交
876
                _writer.WriteEndElement();
P
Pilchie 已提交
877 878
            }

B
beep boop 已提交
879
            _writer.WriteEndElement();
P
Pilchie 已提交
880 881
        }

882
        private void WriteLocals(ISymUnmanagedScope scope)
P
Pilchie 已提交
883
        {
884
            foreach (ISymUnmanagedVariable l in scope.GetLocals())
P
Pilchie 已提交
885
            {
B
beep boop 已提交
886
                _writer.WriteStartElement("local");
887
                _writer.WriteAttributeString("name", l.GetName());
P
Pilchie 已提交
888

889 890 891 892
                // NOTE: VB emits "fake" locals for resumable locals which are actually backed by fields.
                //       These locals always map to the slot #0 which is just a valid number that is 
                //       not used. Only scoping information is used by EE in this case.
                _writer.WriteAttributeString("il_index", CultureInvariantToString(l.GetSlot()));
P
Pilchie 已提交
893

894 895 896 897
                _writer.WriteAttributeString("il_start", AsILOffset(scope.GetStartOffset()));
                _writer.WriteAttributeString("il_end", AsILOffset(scope.GetEndOffset()));
                _writer.WriteAttributeString("attributes", CultureInvariantToString(l.GetAttributes()));
                _writer.WriteEndElement();
P
Pilchie 已提交
898
            }
899

T
Tomas Matousek 已提交
900
            foreach (ISymUnmanagedConstant constant in scope.GetConstants())
P
Pilchie 已提交
901
            {
T
Tomas Matousek 已提交
902 903 904 905
                string name = constant.GetName();
                var signature = constant.GetSignature();
                object value = constant.GetValue();

B
beep boop 已提交
906
                _writer.WriteStartElement("constant");
T
Tomas Matousek 已提交
907 908 909 910 911 912 913
                _writer.WriteAttributeString("name", name);

                if (value is int &&
                    (int)value == 0 &&
                    (signature[0] == (byte)ConstantTypeCode.NullReference ||
                     signature[0] == (int)SignatureTypeCode.Object ||
                     signature[0] == (int)SignatureTypeCode.String ||
914
                     (signature.Length > 2 && signature[0] == (int)SignatureTypeCode.GenericTypeInstance && signature[1] == (byte)ConstantTypeCode.NullReference)))
P
Pilchie 已提交
915
                {
T
Tomas Matousek 已提交
916
                    _writer.WriteAttributeString("value", "null");
P
Pilchie 已提交
917

T
Tomas Matousek 已提交
918
                    if (signature[0] == (int)SignatureTypeCode.String)
P
Pilchie 已提交
919
                    {
T
Tomas Matousek 已提交
920 921 922 923 924 925 926 927
                        _writer.WriteAttributeString("type", "String");
                    }
                    else if (signature[0] == (int)SignatureTypeCode.Object)
                    {
                        _writer.WriteAttributeString("type", "Object");
                    }
                    else
                    {
928
                        _writer.WriteAttributeString("signature", FormatSignature(signature));
P
Pilchie 已提交
929
                    }
T
Tomas Matousek 已提交
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
                }
                else if (value == null)
                {
                    // empty string
                    if (signature[0] == (byte)SignatureTypeCode.String)
                    {
                        _writer.WriteAttributeString("value", "");
                        _writer.WriteAttributeString("type", "String");
                    }
                    else
                    {
                        _writer.WriteAttributeString("value", "null");
                        _writer.WriteAttributeString("unknown-signature", BitConverter.ToString(signature.ToArray()));
                    }
                }
                else if (value is decimal)
                {
                    // TODO: check that the signature is a TypeRef
                    _writer.WriteAttributeString("value", ((decimal)value).ToString(CultureInfo.InvariantCulture));
                    _writer.WriteAttributeString("type", value.GetType().Name);
                }
                else if (value is double && signature[0] != (byte)SignatureTypeCode.Double)
                {
                    // TODO: check that the signature is a TypeRef
                    _writer.WriteAttributeString("value", DateTimeUtilities.ToDateTime((double)value).ToString(CultureInfo.InvariantCulture));
                    _writer.WriteAttributeString("type", "DateTime");
                }
                else
                {
959 960 961
                    string str = value as string;
                    if (str != null)
                    {
T
Tomas Matousek 已提交
962
                        _writer.WriteAttributeString("value", StringUtilities.EscapeNonPrintableCharacters(str));
963 964 965 966 967
                    }
                    else
                    {
                        _writer.WriteAttributeString("value", string.Format(CultureInfo.InvariantCulture, "{0}", value));
                    }
P
Pilchie 已提交
968

T
Tomas Matousek 已提交
969
                    var runtimeType = GetConstantRuntimeType(signature);
J
Jared Parsons 已提交
970
                    if (runtimeType == null &&
T
Tomas Matousek 已提交
971 972 973
                        (value is sbyte || value is byte || value is short || value is ushort ||
                         value is int || value is uint || value is long || value is ulong))
                    {
974
                        _writer.WriteAttributeString("signature", FormatSignature(signature));
T
Tomas Matousek 已提交
975 976 977 978 979 980 981 982 983 984
                    }
                    else if (runtimeType == value.GetType())
                    {
                        _writer.WriteAttributeString("type", ((SignatureTypeCode)signature[0]).ToString());
                    }
                    else
                    {
                        _writer.WriteAttributeString("runtime-type", value.GetType().Name);
                        _writer.WriteAttributeString("unknown-signature", BitConverter.ToString(signature.ToArray()));
                    }
P
Pilchie 已提交
985
                }
T
Tomas Matousek 已提交
986 987

                _writer.WriteEndElement();
P
Pilchie 已提交
988 989
            }
        }
990
        
991 992
        private unsafe string FormatSignature(ImmutableArray<byte> signature)
        {
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
            fixed (byte* sigPtr = signature.ToArray())
            {
                var sigReader = new BlobReader(sigPtr, signature.Length);
                var provider = new SignatureVisualizer(_metadataReader);
                return SignatureDecoder.DecodeType(ref sigReader, provider);
            }
        }

        private sealed class SignatureVisualizer : ISignatureTypeProvider<string>
        {
            private readonly MetadataReader _reader;

            public SignatureVisualizer(MetadataReader reader)
            {
                _reader = reader;
            }

            public MetadataReader Reader => _reader;

            public string GetArrayType(string elementType, ArrayShape shape)
            {
                return elementType + "[" + new string(',', shape.Rank) + "]";
            }

            public string GetByReferenceType(string elementType)
            {
                return elementType + "&";  
            }

            public string GetFunctionPointerType(MethodSignature<string> signature)
            {
                // TODO:
                return "method-ptr"; 
            }

            public string GetGenericInstance(string genericType, ImmutableArray<string> typeArguments)
            {
                // using {} since the result is embedded in XML
                return genericType + "{" + string.Join(", ", typeArguments) + "}";
            }

            public string GetGenericMethodParameter(int index)
            {
                return "!!" + index;
            }

            public string GetGenericTypeParameter(int index)
            {
                return "!" + index;
            }

            public string GetModifiedType(string unmodifiedType, ImmutableArray<CustomModifier<string>> customModifiers)
            {
                return string.Join(" ", customModifiers.Select(mod => (mod.IsRequired ? "modreq(" : "modopt(") + mod.Type + ")")) + 
                    unmodifiedType;
            }

            public string GetPinnedType(string elementType)
            {
                return "pinned " + elementType;
            }

            public string GetPointerType(string elementType)
            {
                return elementType + "*";
            }

            public string GetPrimitiveType(PrimitiveTypeCode typeCode)
            {
                return typeCode.ToString();
            }

            public string GetSZArrayType(string elementType)
            {
                return elementType + "[]";
            }

            public string GetTypeFromDefinition(TypeDefinitionHandle handle)
            {
                var typeDef = _reader.GetTypeDefinition(handle);
                var name = _reader.GetString(typeDef.Name);
                return typeDef.Namespace.IsNil ? name : _reader.GetString(typeDef.Namespace) + "." + name;
            }

            public string GetTypeFromReference(TypeReferenceHandle handle)
            {
                var typeRef = _reader.GetTypeReference(handle);
                var name = _reader.GetString(typeRef.Name);
                return typeRef.Namespace.IsNil ? name : _reader.GetString(typeRef.Namespace) + "." + name;
            }
1083 1084
        }

T
Tomas Matousek 已提交
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
        private static Type GetConstantRuntimeType(ImmutableArray<byte> signature)
        {
            switch ((SignatureTypeCode)signature[0])
            {
                case SignatureTypeCode.Boolean:
                case SignatureTypeCode.Byte:
                case SignatureTypeCode.SByte:
                case SignatureTypeCode.Int16:
                    return typeof(short);

                case SignatureTypeCode.Char:
                case SignatureTypeCode.UInt16:
                    return typeof(ushort);

                case SignatureTypeCode.Int32:
                    return typeof(int);

                case SignatureTypeCode.UInt32:
                    return typeof(uint);

                case SignatureTypeCode.Int64:
                    return typeof(long);

                case SignatureTypeCode.UInt64:
                    return typeof(ulong);

                case SignatureTypeCode.Single:
                    return typeof(float);

                case SignatureTypeCode.Double:
                    return typeof(double);

                case SignatureTypeCode.String:
                    return typeof(string);
            }

            return null;
        }

P
Pilchie 已提交
1124 1125 1126
        // 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).        
1127
        private void WriteSequencePoints(ISymUnmanagedMethod method)
P
Pilchie 已提交
1128
        {
1129
            var sequencePoints = method.GetSequencePoints();
1130 1131 1132 1133 1134 1135
            if (sequencePoints.Length == 0)
            {
                return;
            }

            _writer.WriteStartElement("sequencePoints");
1136

P
Pilchie 已提交
1137
            // Write out sequence points
1138
            foreach (var sequencePoint in sequencePoints)
P
Pilchie 已提交
1139
            {
B
beep boop 已提交
1140 1141
                _writer.WriteStartElement("entry");
                _writer.WriteAttributeString("offset", AsILOffset(sequencePoint.Offset));
P
Pilchie 已提交
1142

1143
                if (sequencePoint.IsHidden)
P
Pilchie 已提交
1144
                {
T
TomasMatousek 已提交
1145 1146
                    if (sequencePoint.StartLine != sequencePoint.EndLine || sequencePoint.StartColumn != 0 || sequencePoint.EndColumn != 0)
                    {
B
beep boop 已提交
1147
                        _writer.WriteAttributeString("hidden", "invalid");
T
TomasMatousek 已提交
1148 1149 1150
                    }
                    else
                    {
B
beep boop 已提交
1151
                        _writer.WriteAttributeString("hidden", XmlConvert.ToString(true));
T
TomasMatousek 已提交
1152 1153 1154 1155
                    }
                }
                else
                {
B
beep boop 已提交
1156 1157 1158 1159
                    _writer.WriteAttributeString("startLine", CultureInvariantToString(sequencePoint.StartLine));
                    _writer.WriteAttributeString("startColumn", CultureInvariantToString(sequencePoint.StartColumn));
                    _writer.WriteAttributeString("endLine", CultureInvariantToString(sequencePoint.EndLine));
                    _writer.WriteAttributeString("endColumn", CultureInvariantToString(sequencePoint.EndColumn));
P
Pilchie 已提交
1160 1161
                }

1162
                int documentId;
B
beep boop 已提交
1163 1164
                _fileMapping.TryGetValue(sequencePoint.Document.GetName(), out documentId);
                _writer.WriteAttributeString("document", CultureInvariantToString(documentId));
P
Pilchie 已提交
1165

B
beep boop 已提交
1166
                _writer.WriteEndElement();
P
Pilchie 已提交
1167 1168
            }

B
beep boop 已提交
1169
            _writer.WriteEndElement(); // sequencepoints
P
Pilchie 已提交
1170 1171 1172 1173 1174 1175 1176
        }

        // Write all docs, and add to the m_fileMapping list.
        // Other references to docs will then just refer to this list.
        private void WriteDocList()
        {
            int id = 0;
1177
            foreach (ISymUnmanagedDocument doc in _symReader.GetDocuments())
P
Pilchie 已提交
1178
            {
1179
                string name = doc.GetName();
P
Pilchie 已提交
1180

1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
                // Native PDB doesn't allow no-name documents. SymWriter silently ignores them.
                // In Portable PDB all methods must be contained in a document, whose name may be empty. Skip such document.
                if (name.Length == 0)
                {
                    continue;
                }

                if (id == 0)
                {
                    _writer.WriteStartElement("files");
                }

P
Pilchie 已提交
1193
                // Symbol store may give out duplicate documents. We'll fold them here
B
beep boop 已提交
1194
                if (_fileMapping.ContainsKey(name))
P
Pilchie 已提交
1195
                {
B
beep boop 已提交
1196
                    _writer.WriteComment("There is a duplicate entry for: " + name);
P
Pilchie 已提交
1197 1198 1199 1200
                    continue;
                }

                id++;
B
beep boop 已提交
1201
                _fileMapping.Add(name, id);
P
Pilchie 已提交
1202

B
beep boop 已提交
1203
                _writer.WriteStartElement("file");
P
Pilchie 已提交
1204

B
beep boop 已提交
1205 1206 1207 1208 1209
                _writer.WriteAttributeString("id", CultureInvariantToString(id));
                _writer.WriteAttributeString("name", name);
                _writer.WriteAttributeString("language", doc.GetLanguage().ToString());
                _writer.WriteAttributeString("languageVendor", doc.GetLanguageVendor().ToString());
                _writer.WriteAttributeString("documentType", doc.GetDocumentType().ToString());
P
Pilchie 已提交
1210

1211
                var checkSum = string.Concat(doc.GetChecksum().Select(b => string.Format("{0,2:X}", b) + ", "));
1212 1213 1214

                if (!string.IsNullOrEmpty(checkSum))
                {
B
beep boop 已提交
1215 1216
                    _writer.WriteAttributeString("checkSumAlgorithmId", doc.GetHashAlgorithm().ToString());
                    _writer.WriteAttributeString("checkSum", checkSum);
P
Pilchie 已提交
1217 1218
                }

B
beep boop 已提交
1219
                _writer.WriteEndElement(); // file
P
Pilchie 已提交
1220
            }
1221 1222 1223 1224 1225

            if (id > 0)
            {
                _writer.WriteEndElement(); // files
            }
P
Pilchie 已提交
1226 1227 1228 1229
        }

        private void WriteAllMethodSpans()
        {
B
beep boop 已提交
1230
            _writer.WriteStartElement("method-spans");
P
Pilchie 已提交
1231

1232
            foreach (ISymUnmanagedDocument doc in _symReader.GetDocuments())
P
Pilchie 已提交
1233
            {
1234
                foreach (ISymUnmanagedMethod method in _symReader.GetMethodsInDocument(doc))
P
Pilchie 已提交
1235
                {
B
beep boop 已提交
1236
                    _writer.WriteStartElement("method");
P
Pilchie 已提交
1237

1238
                    WriteMethodAttributes(method.GetToken(), isReference: true);
P
Pilchie 已提交
1239

1240
                    foreach (var methodDocument in method.GetDocumentsForMethod())
P
Pilchie 已提交
1241
                    {
B
beep boop 已提交
1242
                        _writer.WriteStartElement("document");
1243

P
Pilchie 已提交
1244
                        int startLine, endLine;
1245
                        method.GetSourceExtentInDocument(methodDocument, out startLine, out endLine);
P
Pilchie 已提交
1246

B
beep boop 已提交
1247 1248
                        _writer.WriteAttributeString("startLine", startLine.ToString());
                        _writer.WriteAttributeString("endLine", endLine.ToString());
P
Pilchie 已提交
1249

B
beep boop 已提交
1250
                        _writer.WriteEndElement();
P
Pilchie 已提交
1251 1252
                    }

B
beep boop 已提交
1253
                    _writer.WriteEndElement();
P
Pilchie 已提交
1254 1255 1256
                }
            }

B
beep boop 已提交
1257
            _writer.WriteEndElement();
P
Pilchie 已提交
1258 1259 1260 1261 1262
        }

        // Write out a reference to the entry point method (if one exists)
        private void WriteEntryPoint()
        {
1263
            int token = _symReader.GetUserEntryPoint();
1264
            if (token != 0)
P
Pilchie 已提交
1265
            {
B
beep boop 已提交
1266
                _writer.WriteStartElement("entryPoint");
1267
                WriteMethodAttributes(token, isReference: true);
B
beep boop 已提交
1268
                _writer.WriteEndElement();
P
Pilchie 已提交
1269 1270 1271 1272 1273 1274
            }
        }

        // Write out XML snippet to refer to the given method.
        private void WriteMethodAttributes(int token, bool isReference)
        {
B
beep boop 已提交
1275
            if ((_options & PdbToXmlOptions.ResolveTokens) != 0)
P
Pilchie 已提交
1276 1277 1278 1279 1280
            {
                var handle = MetadataTokens.Handle(token);

                try
                {
A
angocke 已提交
1281
                    switch (handle.Kind)
P
Pilchie 已提交
1282
                    {
A
angocke 已提交
1283 1284
                        case HandleKind.MethodDefinition:
                            WriteResolvedToken((MethodDefinitionHandle)handle, isReference);
P
Pilchie 已提交
1285 1286
                            break;

A
angocke 已提交
1287
                        case HandleKind.MemberReference:
P
Pilchie 已提交
1288 1289 1290 1291 1292
                            WriteResolvedToken((MemberReferenceHandle)handle);
                            break;

                        default:
                            WriteToken(token);
B
beep boop 已提交
1293
                            _writer.WriteAttributeString("error", string.Format("Unexpected token type: {0}", handle.Kind));
P
Pilchie 已提交
1294 1295 1296 1297 1298
                            break;
                    }
                }
                catch (BadImageFormatException e) // TODO: filter
                {
B
beep boop 已提交
1299
                    if ((_options & PdbToXmlOptions.ThrowOnError) != 0)
P
Pilchie 已提交
1300 1301 1302 1303 1304
                    {
                        throw;
                    }

                    WriteToken(token);
B
beep boop 已提交
1305
                    _writer.WriteAttributeString("metadata-error", e.Message);
P
Pilchie 已提交
1306 1307 1308
                }
            }

B
beep boop 已提交
1309
            if ((_options & PdbToXmlOptions.IncludeTokens) != 0)
P
Pilchie 已提交
1310 1311 1312 1313 1314
            {
                WriteToken(token);
            }
        }

A
angocke 已提交
1315
        private static string GetQualifiedMethodName(MetadataReader metadataReader, MethodDefinitionHandle methodHandle)
P
Pilchie 已提交
1316
        {
A
angocke 已提交
1317 1318
            var method = metadataReader.GetMethodDefinition(methodHandle);
            var containingTypeHandle = method.GetDeclaringType();
P
Pilchie 已提交
1319 1320 1321 1322 1323 1324 1325

            string fullTypeName = GetFullTypeName(metadataReader, containingTypeHandle);
            string methodName = metadataReader.GetString(method.Name);

            return fullTypeName != null ? fullTypeName + "." + methodName : methodName;
        }

A
angocke 已提交
1326
        private void WriteResolvedToken(MethodDefinitionHandle methodHandle, bool isReference)
P
Pilchie 已提交
1327
        {
B
beep boop 已提交
1328
            var method = _metadataReader.GetMethodDefinition(methodHandle);
P
Pilchie 已提交
1329 1330

            // type name
A
angocke 已提交
1331
            var containingTypeHandle = method.GetDeclaringType();
B
beep boop 已提交
1332
            var fullName = GetFullTypeName(_metadataReader, containingTypeHandle);
P
Pilchie 已提交
1333 1334
            if (fullName != null)
            {
B
beep boop 已提交
1335
                _writer.WriteAttributeString(isReference ? "declaringType" : "containingType", fullName);
P
Pilchie 已提交
1336 1337 1338
            }

            // method name
B
beep boop 已提交
1339
            _writer.WriteAttributeString(isReference ? "methodName" : "name", _metadataReader.GetString(method.Name));
P
Pilchie 已提交
1340 1341

            // parameters:
T
TomasMatousek 已提交
1342
            var parameterNames = (from paramHandle in method.GetParameters()
B
beep boop 已提交
1343
                                  let parameter = _metadataReader.GetParameter(paramHandle)
T
TomasMatousek 已提交
1344
                                  where parameter.SequenceNumber > 0 // exclude return parameter
B
beep boop 已提交
1345
                                  select parameter.Name.IsNil ? "?" : _metadataReader.GetString(parameter.Name)).ToArray();
P
Pilchie 已提交
1346

T
TomasMatousek 已提交
1347 1348
            if (parameterNames.Length > 0)
            {
B
beep boop 已提交
1349
                _writer.WriteAttributeString("parameterNames", string.Join(", ", parameterNames));
T
TomasMatousek 已提交
1350
            }
P
Pilchie 已提交
1351 1352 1353 1354
        }

        private void WriteResolvedToken(MemberReferenceHandle memberRefHandle)
        {
B
beep boop 已提交
1355
            var memberRef = _metadataReader.GetMemberReference(memberRefHandle);
P
Pilchie 已提交
1356 1357

            // type name
B
beep boop 已提交
1358
            string fullName = GetFullTypeName(_metadataReader, memberRef.Parent);
P
Pilchie 已提交
1359 1360
            if (fullName != null)
            {
B
beep boop 已提交
1361
                _writer.WriteAttributeString("declaringType", fullName);
P
Pilchie 已提交
1362 1363 1364
            }

            // method name
B
beep boop 已提交
1365
            _writer.WriteAttributeString("methodName", _metadataReader.GetString(memberRef.Name));
P
Pilchie 已提交
1366 1367 1368 1369 1370 1371 1372
        }

        private static bool IsNested(TypeAttributes flags)
        {
            return (flags & ((TypeAttributes)0x00000006)) != 0;
        }

1373
        private static string GetFullTypeName(MetadataReader metadataReader, EntityHandle handle)
P
Pilchie 已提交
1374 1375 1376 1377 1378 1379
        {
            if (handle.IsNil)
            {
                return null;
            }

A
angocke 已提交
1380
            if (handle.Kind == HandleKind.TypeDefinition)
P
Pilchie 已提交
1381
            {
A
angocke 已提交
1382
                var type = metadataReader.GetTypeDefinition((TypeDefinitionHandle)handle);
P
Pilchie 已提交
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
                string name = metadataReader.GetString(type.Name);

                while (IsNested(type.Attributes))
                {
                    var enclosingType = metadataReader.GetTypeDefinition(type.GetDeclaringType());
                    name = metadataReader.GetString(enclosingType.Name) + "+" + name;
                    type = enclosingType;
                }

                if (type.Namespace.IsNil)
                {
                    return name;
                }

                return metadataReader.GetString(type.Namespace) + "." + name;
            }

A
angocke 已提交
1400
            if (handle.Kind == HandleKind.TypeReference)
P
Pilchie 已提交
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414
            {
                var typeRef = metadataReader.GetTypeReference((TypeReferenceHandle)handle);
                string name = metadataReader.GetString(typeRef.Name);
                if (typeRef.Namespace.IsNil)
                {
                    return name;
                }

                return metadataReader.GetString(typeRef.Namespace) + "." + name;
            }

            return string.Format("<unexpected token kind: {0}>", AsToken(metadataReader.GetToken(handle)));
        }

1415
#region Utils
P
Pilchie 已提交
1416 1417 1418

        private void WriteToken(int token)
        {
B
beep boop 已提交
1419
            _writer.WriteAttributeString("token", AsToken(token));
P
Pilchie 已提交
1420 1421 1422 1423
        }

        internal static string AsToken(int i)
        {
1424
            return string.Format(CultureInfo.InvariantCulture, "0x{0:x}", i);
P
Pilchie 已提交
1425 1426
        }

1427
        internal static string AsILOffset(int i)
P
Pilchie 已提交
1428
        {
1429
            return string.Format(CultureInfo.InvariantCulture, "0x{0:x}", i);
P
Pilchie 已提交
1430 1431 1432 1433 1434 1435 1436
        }

        internal static string CultureInvariantToString(int input)
        {
            return input.ToString(CultureInfo.InvariantCulture);
        }

1437
#endregion
P
Pilchie 已提交
1438 1439
    }
}