/// <summary> /// Contains a list of buckets, each of which contains a number of flags, a slot ID, and a name. /// TODO: comment when the structure is understood. /// </summary> /// <remarks> /// Appears when there are dynamic locals. /// </remarks> private void WriteDynamicLocalsCustomDebugInfo(CustomDebugInfoRecord record) { Debug.Assert(record.Kind == CustomDebugInfoKind.DynamicLocals); writer.WriteStartElement("dynamicLocals"); var buckets = CDI.DecodeDynamicLocalsRecord(record.Data); foreach (DynamicLocalBucket bucket in buckets) { ulong flags = bucket.Flags; int flagCount = bucket.FlagCount; PooledStringBuilder pooled = PooledStringBuilder.GetInstance(); StringBuilder flagsBuilder = pooled.Builder; for (int f = 0; f < flagCount; f++) { flagsBuilder.Append((flags >> f) & 1UL); } writer.WriteStartElement("bucket"); writer.WriteAttributeString("flagCount", flagCount.ToString()); writer.WriteAttributeString("flags", pooled.ToStringAndFree()); writer.WriteAttributeString("slotId", bucket.SlotId.ToString()); writer.WriteAttributeString("localName", bucket.Name); writer.WriteEndElement(); //bucket } writer.WriteEndElement(); //dynamicLocals }
/// <summary> /// Contains a name string. /// TODO: comment when the structure is understood. /// </summary> /// <remarks> /// Appears when are iterator methods. /// </remarks> private void WriteForwardIteratorCustomDebugInfo(CustomDebugInfoRecord record) { Debug.Assert(record.Kind == CustomDebugInfoKind.ForwardIterator); writer.WriteStartElement("forwardIterator"); string name = CDI.DecodeForwardIteratorRecord(record.Data); writer.WriteAttributeString("name", name); writer.WriteEndElement(); //forwardIterator }
/// <summary> /// This indicates that further information can be obtained by looking at the custom debug /// info of another method (specified by token). /// </summary> /// <remarks> /// Appears when there are extern aliases and edit-and-continue is disabled. /// Emitting tokens makes tests more fragile. /// </remarks> private void WriteForwardToModuleCustomDebugInfo(CustomDebugInfoRecord record) { Debug.Assert(record.Kind == CustomDebugInfoKind.ForwardToModuleInfo); writer.WriteStartElement("forwardToModule"); int token = CDI.DecodeForwardRecord(record.Data); WriteMethodAttributes(token, isReference: true); writer.WriteEndElement(); //forwardToModule }
/// <summary> /// For each namespace declaration enclosing a method (innermost-to-outermost), there is a count /// of the number of imports in that declaration. /// </summary> /// <remarks> /// There's always at least one entry (for the global namespace). /// </remarks> private void WriteUsingCustomDebugInfo(CustomDebugInfoRecord record) { Debug.Assert(record.Kind == CustomDebugInfoKind.UsingInfo); writer.WriteStartElement("using"); ImmutableArray <short> counts = CDI.DecodeUsingRecord(record.Data); foreach (short importCount in counts) { writer.WriteStartElement("namespace"); writer.WriteAttributeString("usingCount", importCount.ToString()); writer.WriteEndElement(); //namespace } writer.WriteEndElement(); //using }
/// <summary> /// Appears when iterator locals have to lifted into fields. Contains a list of buckets with /// start and end offsets (presumably, into IL). /// TODO: comment when the structure is understood. /// </summary> /// <remarks> /// Appears when there are locals in iterator methods. /// </remarks> private void WriteStatemachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoRecord record) { Debug.Assert(record.Kind == CustomDebugInfoKind.StateMachineHoistedLocalScopes); writer.WriteStartElement("hoistedLocalScopes"); var scopes = CDI.DecodeStateMachineHoistedLocalScopesRecord(record.Data); foreach (StateMachineHoistedLocalScope scope in scopes) { writer.WriteStartElement("slot"); writer.WriteAttributeString("startOffset", AsILOffset(scope.StartOffset)); writer.WriteAttributeString("endOffset", AsILOffset(scope.EndOffset)); writer.WriteEndElement(); //bucket } writer.WriteEndElement(); }
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; var parsingSucceeded = CDI.TryParseVisualBasicImportString(rawName, out alias, out target, out kind, out scope); Debug.Assert(parsingSucceeded); } else { switch (rawName[0]) { case 'U': case 'A': case 'X': case 'Z': case 'E': case 'T': scope = ImportScope.Unspecified; if (!CDI.TryParseCSharpImportString(rawName, out alias, out externAlias, out target, out kind)) { throw new InvalidOperationException(string.Format("Invalid import '{0}'", rawName)); } break; default: externAlias = null; if (!CDI.TryParseVisualBasicImportString(rawName, out alias, out target, out kind, out scope)) { throw new InvalidOperationException(string.Format("Invalid import '{0}'", rawName)); } break; } } } catch (ArgumentException) // TODO: filter { if ((options & PdbToXmlOptions.ThrowOnError) != 0) { throw; } writer.WriteStartElement("invalid-custom-data"); writer.WriteAttributeString("raw", rawName); writer.WriteEndElement(); return; } switch (kind) { case ImportTargetKind.CurrentNamespace: Debug.Assert(alias == null); Debug.Assert(externAlias == null); Debug.Assert(scope == ImportScope.Unspecified); writer.WriteStartElement("currentnamespace"); writer.WriteAttributeString("name", target); writer.WriteEndElement(); // </currentnamespace> break; case ImportTargetKind.DefaultNamespace: Debug.Assert(alias == null); Debug.Assert(externAlias == null); Debug.Assert(scope == ImportScope.Unspecified); writer.WriteStartElement("defaultnamespace"); writer.WriteAttributeString("name", target); writer.WriteEndElement(); // </defaultnamespace> break; case ImportTargetKind.MethodToken: Debug.Assert(alias == null); Debug.Assert(externAlias == null); Debug.Assert(scope == ImportScope.Unspecified); int token = Convert.ToInt32(target); writer.WriteStartElement("importsforward"); WriteMethodAttributes(token, isReference: true); writer.WriteEndElement(); // </importsforward> break; case ImportTargetKind.XmlNamespace: Debug.Assert(externAlias == null); writer.WriteStartElement("xmlnamespace"); writer.WriteAttributeString("prefix", alias); writer.WriteAttributeString("name", target); WriteScopeAttribute(scope); writer.WriteEndElement(); // </xmlnamespace> break; case ImportTargetKind.NamespaceOrType: Debug.Assert(externAlias == null); writer.WriteStartElement("alias"); writer.WriteAttributeString("name", alias); writer.WriteAttributeString("target", target); writer.WriteAttributeString("kind", "namespace"); // Strange, but retaining to avoid breaking tests. WriteScopeAttribute(scope); writer.WriteEndElement(); // </alias> break; case ImportTargetKind.Namespace: if (alias != null) { writer.WriteStartElement("alias"); writer.WriteAttributeString("name", alias); if (externAlias != null) { writer.WriteAttributeString("qualifier", externAlias); } writer.WriteAttributeString("target", target); writer.WriteAttributeString("kind", "namespace"); Debug.Assert(scope == ImportScope.Unspecified); // Only C# hits this case. writer.WriteEndElement(); // </alias> } else { writer.WriteStartElement("namespace"); if (externAlias != null) { writer.WriteAttributeString("qualifier", externAlias); } writer.WriteAttributeString("name", target); WriteScopeAttribute(scope); writer.WriteEndElement(); // </namespace> } break; case ImportTargetKind.Type: Debug.Assert(externAlias == null); if (alias != null) { writer.WriteStartElement("alias"); writer.WriteAttributeString("name", alias); writer.WriteAttributeString("target", target); writer.WriteAttributeString("kind", "type"); Debug.Assert(scope == ImportScope.Unspecified); // Only C# hits this case. writer.WriteEndElement(); // </alias> } else { writer.WriteStartElement("type"); writer.WriteAttributeString("name", target); WriteScopeAttribute(scope); writer.WriteEndElement(); // </type> } break; case ImportTargetKind.Assembly: Debug.Assert(alias == null); Debug.Assert(scope == ImportScope.Unspecified); if (target == null) { writer.WriteStartElement("extern"); writer.WriteAttributeString("alias", externAlias); writer.WriteEndElement(); // </extern> } else { writer.WriteStartElement("externinfo"); writer.WriteAttributeString("alias", externAlias); writer.WriteAttributeString("assembly", target); writer.WriteEndElement(); // </externinfo> } break; case ImportTargetKind.Defunct: Debug.Assert(alias == null); Debug.Assert(scope == ImportScope.Unspecified); writer.WriteStartElement("defunct"); writer.WriteAttributeString("name", rawName); writer.WriteEndElement(); // </defunct> break; default: Debug.Assert(false, "Unexpected import kind '" + kind + "'"); writer.WriteStartElement("unknown"); writer.WriteAttributeString("name", rawName); writer.WriteEndElement(); // </unknown> break; } }