private void WriteMethod(MethodDefinitionHandle methodHandle) { int token = metadataReader.GetToken(methodHandle); byte[] cdi = pdbReader.SymbolReader.GetCustomDebugInfo(token, methodVersion: 0); ISymUnmanagedMethod method = pdbReader.SymbolReader.GetMethod(token); if (cdi == null && method == null) { // no debug info for the method return; } writer.WriteStartElement("method"); WriteMethodAttributes(token, isReference: false); if (cdi != null) { WriteCustomDebugInfo(cdi); } if (method != null) { WriteSequencePoints(method); // TODO (tomat): Ideally this would be done in a separate test helper, not in PdbToXml. // verify ISymUnmanagedMethod APIs: var expectedSlotNames = new Dictionary <int, ImmutableArray <string> >(); WriteLocals(method, expectedSlotNames); var actualSlotNames = method.GetLocalVariableSlots(); Debug.Assert(actualSlotNames.Length == (expectedSlotNames.Count == 0 ? 0 : expectedSlotNames.Keys.Max() + 1)); int i = 0; foreach (var slotName in actualSlotNames) { if (slotName == null) { Debug.Assert(!expectedSlotNames.ContainsKey(i)); } else { Debug.Assert(expectedSlotNames[i].Contains(slotName)); } i++; } ImmutableArray <ISymUnmanagedScope> children = method.GetRootScope().GetScopes(); if (children.Length != 0) { WriteScopes(children[0]); } WriteAsyncInfo(method); } writer.WriteEndElement(); // method }
// Write all the locals in the given method out to an XML file. // Since the symbol store represents the locals in a recursive scope structure, we need to walk a tree. // Although the locals are technically a hierarchy (based off nested scopes), it's easiest for clients // if we present them as a linear list. We will provide the range for each local's scope so that somebody // could reconstruct an approximation of the scope tree. The reconstruction may not be exact. // (Note this would still break down if you had an empty scope nested in another scope. private void WriteLocals(ISymUnmanagedMethod method, Dictionary <int, ImmutableArray <string> > slotNames) { writer.WriteStartElement("locals"); // If there are no locals, then this element will just be empty. WriteLocalsHelper(method.GetRootScope(), slotNames, includeChildScopes: true); writer.WriteEndElement(); }
public static ISymUnmanagedScope GetRootScope(this ISymUnmanagedMethod method) { ISymUnmanagedScope scope; method.GetRootScope(out scope); return(scope); }
public static ISymUnmanagedScope GetRootScope(this ISymUnmanagedMethod method) { ISymUnmanagedScope scope; int hr = method.GetRootScope(out scope); ThrowExceptionForHR(hr); return(scope); }
internal static void GetAllScopes( this ISymUnmanagedMethod method, ArrayBuilder <ISymUnmanagedScope> allScopes, ArrayBuilder <ISymUnmanagedScope> containingScopes, int offset, bool isScopeEndInclusive) { GetAllScopes(method.GetRootScope(), allScopes, containingScopes, offset, isScopeEndInclusive); }
public int GetRootScope(out ISymUnmanagedScope retVal) { _method.GetRootScope(out retVal); if (retVal != null) { retVal = new SymScope(_reader, retVal); } return(SymUnmanagedReaderExtensions.S_OK); }
public static ISymUnmanagedScope GetRootScope(this ISymUnmanagedMethod method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } ISymUnmanagedScope scope; ThrowExceptionForHR(method.GetRootScope(out scope)); return(scope); }
internal static ImmutableArray <string> GetLocalVariableSlots(this ISymUnmanagedMethod method) { var builder = ImmutableArray.CreateBuilder <string>(); ISymUnmanagedScope rootScope = method.GetRootScope(); ForEachLocalVariableRecursive(rootScope, offset: -1, isScopeEndInclusive: false, action: local => { var slot = local.GetSlot(); while (builder.Count <= slot) { builder.Add(null); } var name = local.GetName(); builder[slot] = name; }); return(builder.ToImmutable()); }
internal static ImmutableArray <string> GetLocalVariableSlots(this ISymUnmanagedMethod method, int offset = -1) { char[] nameBuffer = null; string[] result = null; int maxSlot = -1; ISymUnmanagedScope rootScope = method.GetRootScope(); ISymUnmanagedVariable[] localsBuffer = null; ForEachLocalVariableRecursive(rootScope, offset, ref localsBuffer, local => { int nameLength; local.GetName(0, out nameLength, null); if (nameLength > 0) { EnsureBufferSize(ref nameBuffer, nameLength); local.GetName(nameLength, out nameLength, nameBuffer); int slot; local.GetAddressField1(out slot); if (maxSlot < slot) { maxSlot = slot; } EnsureBufferSize(ref result, slot + 1); // nameLength is NUL-terminated Debug.Assert(nameBuffer[nameLength - 1] == '\0'); result[slot] = new string(nameBuffer, 0, nameLength - 1); } }); if (result == null) { return(ImmutableArray.Create <string>()); } return(ImmutableArray.Create(result, 0, maxSlot + 1)); }
/// <summary> /// Get the (unprocessed) import strings for a given method. /// </summary> /// <remarks> /// Doesn't consider forwarding. /// /// CONSIDER: Dev12 doesn't just check the root scope - it digs around to find the best /// match based on the IL offset and then walks up to the root scope (see PdbUtil::GetScopeFromOffset). /// However, it's not clear that this matters, since imports can't be scoped in VB. This is probably /// just based on the way they were extracting locals and constants based on a specific scope. /// </remarks> internal static ImmutableArray <string> GetImportStrings(this ISymUnmanagedMethod method) { if (method == null) { // In rare circumstances (only bad PDBs?) GetMethodByVersion can return null. // If there's no debug info for the method, then no import strings are available. return(ImmutableArray <string> .Empty); } ISymUnmanagedScope rootScope = method.GetRootScope(); if (rootScope == null) { Debug.Assert(false, "Expected a root scope."); return(ImmutableArray <string> .Empty); } ImmutableArray <ISymUnmanagedScope> childScopes = rootScope.GetScopes(); if (childScopes.Length == 0) { // It seems like there should always be at least one child scope, but we've // seen PDBs where that is not the case. return(ImmutableArray <string> .Empty); } // As in NamespaceListWrapper::Init, we only consider namespaces in the first // child of the root scope. ISymUnmanagedScope firstChildScope = childScopes[0]; ImmutableArray <ISymUnmanagedNamespace> namespaces = firstChildScope.GetNamespaces(); if (namespaces.Length == 0) { // It seems like there should always be at least one namespace (i.e. the global // namespace), but we've seen PDBs where that is not the case. return(ImmutableArray <string> .Empty); } return(ImmutableArray.CreateRange(namespaces, n => n.GetName())); }
/// <summary> /// Get the (unprocessed) import strings for a given method. /// </summary> /// <remarks> /// Doesn't consider forwarding. /// </remarks> private static ImmutableArray <string> GetImportStrings(this ISymUnmanagedMethod method) { ISymUnmanagedScope rootScope = method.GetRootScope(); if (rootScope == null) { Debug.Assert(false, "Expected a root scope."); return(ImmutableArray <string> .Empty); } ImmutableArray <ISymUnmanagedScope> childScopes = rootScope.GetScopes(); if (childScopes.Length == 0) { //Debug.Assert(false, "Expected at least one child scope."); // TODO (acasey): Why can't we assume this? return(ImmutableArray <string> .Empty); } // As in NamespaceListWrapper::Init, we only consider namespaces in the first // child of the root scope. ISymUnmanagedScope firstChildScope = childScopes[0]; ImmutableArray <ISymUnmanagedNamespace> namespaces = firstChildScope.GetNamespaces(); if (namespaces.Length == 0) { //Debug.Assert(false, "Expected at least one namespace (i.e. the global namespace)."); // TODO (acasey): Why can't we assume this? return(ImmutableArray <string> .Empty); } ArrayBuilder <string> importsBuilder = ArrayBuilder <string> .GetInstance(namespaces.Length); foreach (ISymUnmanagedNamespace @namespace in namespaces) { importsBuilder.Add(@namespace.GetName()); } return(importsBuilder.ToImmutableAndFree()); }
// Write all the locals in the given method out to an XML file. // Since the symbol store represents the locals in a recursive scope structure, we need to walk a tree. // Although the locals are technically a hierarchy (based off nested scopes), it's easiest for clients // if we present them as a linear list. We will provide the range for each local's scope so that somebody // could reconstruct an approximation of the scope tree. The reconstruction may not be exact. // (Note this would still break down if you had an empty scope nested in another scope. private void WriteLocals(ISymUnmanagedMethod method, Dictionary<int, ImmutableArray<string>> slotNames) { writer.WriteStartElement("locals"); { // If there are no locals, then this element will just be empty. WriteLocalsHelper(method.GetRootScope(), slotNames, includeChildScopes: true); } writer.WriteEndElement(); }
internal static void GetAllScopes(this ISymUnmanagedMethod method, ArrayBuilder <ISymUnmanagedScope> builder, int offset, bool isScopeEndInclusive) { ISymUnmanagedScope scope = method.GetRootScope(); GetAllScopes(scope, builder, offset, isScopeEndInclusive); }