private static void ForEachLocalVariableRecursive( ISymUnmanagedScope scope, int offset, bool isScopeEndInclusive, Action<ISymUnmanagedVariable> action) { Debug.Assert(offset < 0 || scope.IsInScope(offset, isScopeEndInclusive)); // apply action on locals of the current scope: foreach (var local in scope.GetLocals()) { action(local); } // recurse: foreach (var child in scope.GetChildren()) { if (offset < 0 || child.IsInScope(offset, isScopeEndInclusive)) { ForEachLocalVariableRecursive(child, offset, isScopeEndInclusive, action); if (offset >= 0) { return; } } } }
public ISymbolVariable[] GetLocals() { int count; m_target.GetLocals(0, out count, null); ISymUnmanagedVariable[] uVariables = new ISymUnmanagedVariable[count]; m_target.GetLocals(count, out count, uVariables); int i; ISymbolVariable[] variables = new ISymbolVariable[count]; for (i = 0; i < count; i++) { variables[i] = new SymVariable(uVariables[i]); } return(variables); }
public ISymbolVariable[] GetLocals() { int size; HRESULT.ThrowOnFailure(_unmanaged.GetLocals(0, out size, null)); var unmanagedVars = new ISymUnmanagedVariable[size]; HRESULT.ThrowOnFailure(_unmanaged.GetLocals(unmanagedVars.Length, out size, unmanagedVars)); var variables = new ISymbolVariable[size]; for (int i = 0; i < size; i++) { variables[i] = new SymbolVariable(unmanagedVars[i]); } return(variables); }
private List <DebugLocalVariableInfo> GetLocalVariablesInScope(ISymUnmanagedScope symScope) { List <DebugLocalVariableInfo> vars = new List <DebugLocalVariableInfo>(); foreach (ISymUnmanagedVariable symVar in symScope.GetLocals()) { ISymUnmanagedVariable symVarCopy = symVar; int start; SignatureReader sigReader = new SignatureReader(symVar.GetSignature()); LocalVarSig.LocalVariable locVarSig = sigReader.ReadLocalVariable(sigReader.Blob, 0, out start); DebugType locVarType = DebugType.CreateFromSignature(this.DebugModule, locVarSig.Type, declaringType); // Compiler generated? // NB: Display class does not have the compiler-generated flag if ((symVar.GetAttributes() & 1) == 1 || symVar.GetName().StartsWith("CS$")) { // Get display class from local variable if (locVarType.IsDisplayClass) { AddCapturedLocalVariables( vars, (int)symScope.GetStartOffset(), (int)symScope.GetEndOffset(), delegate(StackFrame context) { return(GetLocalVariableValue(context, symVarCopy)); }, locVarType ); } } else { DebugLocalVariableInfo locVar = new DebugLocalVariableInfo( symVar.GetName(), (int)symVar.GetAddressField1(), // symVar also has Get*Offset methods, but the are not implemented (int)symScope.GetStartOffset(), (int)symScope.GetEndOffset(), locVarType, delegate(StackFrame context) { return(GetLocalVariableValue(context, symVarCopy)); } ); vars.Add(locVar); } } foreach (ISymUnmanagedScope childScope in symScope.GetChildren()) { vars.AddRange(GetLocalVariablesInScope(childScope)); } return(vars); }
private static void ForEachLocalVariableRecursive( ISymUnmanagedScope scope, int offset, ref ISymUnmanagedVariable[] localsBuffer, Action <ISymUnmanagedVariable> action) { Debug.Assert((offset < 0) || scope.IsInScope(offset)); // apply action on locals of the current scope: int localCount; scope.GetLocalCount(out localCount); if (localCount > 0) { EnsureBufferSize(ref localsBuffer, localCount); scope.GetLocals(localCount, out localCount, localsBuffer); for (int i = 0; i < localCount; i++) { action(localsBuffer[i]); } } // recurse: int childCount; scope.GetChildren(0, out childCount, null); if (childCount > 0) { var children = new ISymUnmanagedScope[childCount]; scope.GetChildren(childCount, out childCount, children); foreach (var child in children) { if ((offset < 0) || child.IsInScope(offset)) { ForEachLocalVariableRecursive(child, offset, ref localsBuffer, action); if (offset >= 0) { return; } } } } }
/// <summary> /// Get definitions of local variables in scope. /// </summary> /// <param name="scope">Interface refering to desired scope.</param> /// <param name="index">Index pointing to the last read variable.</param> /// <param name="definitions">List of definitions, where found variable definition are placed.</param> private void getDefinitionsForScope(ISymUnmanagedScope scope, ref int index, List <LocalVarDefinition> definitions) { ISymUnmanagedVariable[] variables = scope.GetLocals(); foreach (ISymUnmanagedVariable var in variables) { LocalVarDefinition def = new LocalVarDefinition(); def.ilStart = scope.GetStartOffset(); def.ilEnd = scope.GetEndOffset(); def.name = var.GetName(); def.signature = var.GetSignature(); definitions.Add(def); ++index; } foreach (ISymUnmanagedScope cScope in scope.GetChildren()) { getDefinitionsForScope(cScope, ref index, definitions); } }
// // Gather the local details in a scope and then recurse to child scopes // private void ProbeScopeForLocals(List <LocalVariable> variables, ISymUnmanagedScope scope) { int localCount; ThrowExceptionForHR(scope.GetLocalCount(out localCount)); ISymUnmanagedVariable[] locals = new ISymUnmanagedVariable[localCount]; ThrowExceptionForHR(scope.GetLocals(localCount, out localCount, locals)); for (int i = 0; i < localCount; i++) { var local = locals[i]; int slot; ThrowExceptionForHR(local.GetAddressField1(out slot)); int nameLength; ThrowExceptionForHR(local.GetName(0, out nameLength, null)); // nameLength includes terminating '\0' char[] nameBuffer = new char[nameLength]; ThrowExceptionForHR(local.GetName(nameLength, out nameLength, nameBuffer)); int attributes; ThrowExceptionForHR(local.GetAttributes(out attributes)); variables.Add(new LocalVariable() { Slot = slot, Name = new String(nameBuffer, 0, nameLength - 1), CompilerGenerated = (attributes & 0x1) != 0 }); } int childrenCount; ThrowExceptionForHR(scope.GetChildren(0, out childrenCount, null)); ISymUnmanagedScope[] children = new ISymUnmanagedScope[childrenCount]; ThrowExceptionForHR(scope.GetChildren(childrenCount, out childrenCount, children)); for (int i = 0; i < childrenCount; i++) { ProbeScopeForLocals(variables, children[i]); } }
public static ImmutableArray <ISymUnmanagedVariable> GetLocals(this ISymUnmanagedScope scope) { int numAvailable; scope.GetLocalCount(out numAvailable); if (numAvailable == 0) { return(ImmutableArray <ISymUnmanagedVariable> .Empty); } int numRead; var locals = new ISymUnmanagedVariable[numAvailable]; scope.GetLocals(numAvailable, out numRead, locals); if (numRead != numAvailable) { throw new InvalidOperationException(string.Format("Read only {0} of {1} locals.", numRead, numAvailable)); } return(ImmutableArray.Create(locals)); }
private static ISymUnmanagedVariable[] GetLocalsInternal(ISymUnmanagedScope scope) { int numAvailable; scope.GetLocalCount(out numAvailable); if (numAvailable == 0) { return(null); } int numRead; var locals = new ISymUnmanagedVariable[numAvailable]; scope.GetLocals(numAvailable, out numRead, locals); if (numRead != numAvailable) { throw new InvalidOperationException(string.Format("Read only {0} of {1} locals.", numRead, numAvailable)); } return(locals); }
public IEnumerable <ILLocalVariable> GetLocalVariables(IMethod method) { List <ILLocalVariable> vars = new List <ILLocalVariable>(); var symMethod = method.GetSymMethod(); if (symMethod == null) { return(vars); } Stack <ISymUnmanagedScope> scopes = new Stack <ISymUnmanagedScope>(); scopes.Push(symMethod.GetRootScope()); while (scopes.Count > 0) { ISymUnmanagedScope scope = scopes.Pop(); foreach (ISymUnmanagedVariable symVar in scope.GetLocals()) { int index = (int)symVar.GetAddressField1(); vars.Add(new ILLocalVariable() { Index = index, Type = method.GetLocalVariableType(index), Name = symVar.GetName(), IsCompilerGenerated = (symVar.GetAttributes() & 1) == 1, // symVar also has Get*Offset methods, but the are not implemented ILRanges = new [] { new ILRange() { From = (int)scope.GetStartOffset(), To = (int)scope.GetEndOffset() } } }); } foreach (ISymUnmanagedScope childScope in scope.GetChildren()) { scopes.Push(childScope); } } return(vars); }
private static void SerializeScope( MetadataBuilder metadataBuilder, MetadataModel metadataModel, MethodDefinitionHandle methodHandle, ImportScopeHandle importScopeHandle, ISymUnmanagedScope symScope, Dictionary <int, DynamicLocalInfo> dynamicSlots, Dictionary <string, DynamicLocalInfo> dynamicNames, bool vbSemantics, ref LocalVariableHandle lastLocalVariableHandle, ref LocalConstantHandle lastLocalConstantHandle) { // VB Windows PDB encode the range as end-inclusive, // all Portable PDBs use end-exclusive encoding. int start = symScope.GetStartOffset(); int end = symScope.GetEndOffset() + (vbSemantics ? 1 : 0); metadataBuilder.AddLocalScope( method: methodHandle, importScope: importScopeHandle, variableList: NextHandle(lastLocalVariableHandle), constantList: NextHandle(lastLocalConstantHandle), startOffset: start, length: end - start); foreach (var symLocal in symScope.GetLocals()) { int slot = symLocal.GetSlot(); string name = symLocal.GetName(); lastLocalVariableHandle = metadataBuilder.AddLocalVariable( attributes: (LocalVariableAttributes)symLocal.GetAttributes(), index: slot, name: metadataBuilder.GetOrAddString(name)); DynamicLocalInfo dynamicInfo; if (slot > 0 && dynamicSlots.TryGetValue(slot, out dynamicInfo) || slot == 0 && dynamicNames.TryGetValue(name, out dynamicInfo)) { metadataBuilder.AddCustomDebugInformation( parent: lastLocalVariableHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.DynamicLocalVariables), value: SerializeDynamicLocalBlob(metadataBuilder, dynamicInfo)); } } foreach (var symConstant in symScope.GetConstants()) { string name = symConstant.GetName(); object value = symConstant.GetValue(); lastLocalConstantHandle = metadataBuilder.AddLocalConstant( name: metadataBuilder.GetOrAddString(name), signature: SerializeConstantSignature(metadataBuilder, metadataModel, symConstant.GetSignature(), value)); DynamicLocalInfo dynamicInfo; if (dynamicNames.TryGetValue(name, out dynamicInfo)) { metadataBuilder.AddCustomDebugInformation( parent: lastLocalConstantHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.DynamicLocalVariables), value: SerializeDynamicLocalBlob(metadataBuilder, dynamicInfo)); } } int previousChildScopeEnd = start; foreach (ISymUnmanagedScope child in symScope.GetChildren()) { int childScopeStart = child.GetStartOffset(); int childScopeEnd = child.GetEndOffset(); // scopes are properly nested: if (childScopeStart < previousChildScopeEnd || childScopeEnd > end) { // TODO: loc/warning throw new BadImageFormatException($"Invalid scope IL offset range: [{childScopeStart}, {childScopeEnd}), method 0x{MetadataTokens.GetToken(methodHandle):x}."); } previousChildScopeEnd = childScopeEnd; SerializeScope(metadataBuilder, metadataModel, methodHandle, importScopeHandle, child, dynamicSlots, dynamicNames, vbSemantics, ref lastLocalVariableHandle, ref lastLocalConstantHandle); } }
private void WriteLocals(ISymUnmanagedScope scope) { foreach (ISymUnmanagedVariable l in scope.GetLocals()) { _writer.WriteStartElement("local"); _writer.WriteAttributeString("name", l.GetName()); // 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())); _writer.WriteAttributeString("il_start", AsILOffset(scope.GetStartOffset())); _writer.WriteAttributeString("il_end", AsILOffset(scope.GetEndOffset())); _writer.WriteAttributeString("attributes", CultureInvariantToString(l.GetAttributes())); _writer.WriteEndElement(); } foreach (ISymUnmanagedConstant constant in scope.GetConstants()) { string name = constant.GetName(); var signature = constant.GetSignature(); object value = constant.GetValue(); _writer.WriteStartElement("constant"); _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 || signature[0] == (int)SignatureTypeCode.GenericTypeInstance)) { // TODO: 0 for enums nested in a generic class, null for reference type // We need to decode the signature and see if the target type is enum. _writer.WriteAttributeString("value", "null"); if (signature[0] == (int)SignatureTypeCode.String) { _writer.WriteAttributeString("type", "String"); } else if (signature[0] == (int)SignatureTypeCode.Object) { _writer.WriteAttributeString("type", "Object"); } else { // TODO: // A null reference, the type is encoded in the signature. // Ideally we would parse the signature and display the target type name. // That requires MetadataReader vNext though. _writer.WriteAttributeString("signature", BitConverter.ToString(signature.ToArray())); } } 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 { _writer.WriteAttributeString("value", (value as string)?.Replace("\0", "U+0000") ?? string.Format(CultureInfo.InvariantCulture, "{0}", value)); var runtimeType = GetConstantRuntimeType(signature); if (runtimeType == null && (value is sbyte || value is byte || value is short || value is ushort || value is int || value is uint || value is long || value is ulong)) { // TODO: // Enum. // Ideally we would parse the signature and display the target type name. // That requires MetadataReader vNext though. _writer.WriteAttributeString("signature", BitConverter.ToString(signature.ToArray())); } 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())); } } _writer.WriteEndElement(); } }
/// <summary> /// Get definitions of local variables in scope. /// </summary> /// <param name="scope">Interface refering to desired scope.</param> /// <param name="index">Index pointing to the last read variable.</param> /// <param name="definitions">List of definitions, where found variable definition are placed.</param> private void getDefinitionsForScope(ISymUnmanagedScope scope, ref int index, List<LocalVarDefinition> definitions) { ISymUnmanagedVariable[] variables = scope.GetLocals(); foreach (ISymUnmanagedVariable var in variables) { LocalVarDefinition def = new LocalVarDefinition(); def.ilStart = scope.GetStartOffset(); def.ilEnd = scope.GetEndOffset(); def.name = var.GetName(); def.signature = var.GetSignature(); definitions.Add(def); ++index; } foreach (ISymUnmanagedScope cScope in scope.GetChildren()) { getDefinitionsForScope(cScope, ref index, definitions); } }
private void WriteLocals(ISymUnmanagedScope scope) { foreach (ISymUnmanagedVariable l in scope.GetLocals()) { _writer.WriteStartElement("local"); _writer.WriteAttributeString("name", l.GetName()); // 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())); _writer.WriteAttributeString("il_start", AsILOffset(scope.GetStartOffset())); _writer.WriteAttributeString("il_end", AsILOffset(scope.GetEndOffset())); _writer.WriteAttributeString("attributes", CultureInvariantToString(l.GetAttributes())); _writer.WriteEndElement(); } foreach (ISymUnmanagedConstant constant in scope.GetConstants()) { string name = constant.GetName(); var signature = constant.GetSignature(); object value = constant.GetValue(); _writer.WriteStartElement("constant"); _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 || (signature.Length > 2 && signature[0] == (int)SignatureTypeCode.GenericTypeInstance && signature[1] == (byte)ConstantTypeCode.NullReference))) { _writer.WriteAttributeString("value", "null"); if (signature[0] == (int)SignatureTypeCode.String) { _writer.WriteAttributeString("type", "String"); } else if (signature[0] == (int)SignatureTypeCode.Object) { _writer.WriteAttributeString("type", "Object"); } else { _writer.WriteAttributeString("signature", FormatSignature(signature)); } } 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 { string str = value as string; if (str != null) { _writer.WriteAttributeString("value", StringUtilities.EscapeNonPrintableCharacters(str)); } else { _writer.WriteAttributeString("value", string.Format(CultureInfo.InvariantCulture, "{0}", value)); } var runtimeType = GetConstantRuntimeType(signature); if (runtimeType == null && (value is sbyte || value is byte || value is short || value is ushort || value is int || value is uint || value is long || value is ulong)) { _writer.WriteAttributeString("signature", FormatSignature(signature)); } 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())); } } _writer.WriteEndElement(); } }
private void WriteScopes(ISymUnmanagedScope rootScope) { // The root scope is always empty. The first scope opened by SymWriter is the child of the root scope. if (rootScope.GetNamespaces().IsEmpty && rootScope.GetLocals().IsEmpty && rootScope.GetConstants().IsEmpty) { foreach (ISymUnmanagedScope child in rootScope.GetScopes()) { WriteScope(child, isRoot: false); } } else { // This shouldn't be executed for PDBs generated via SymWriter. WriteScope(rootScope, isRoot: true); } }
static ICorDebugValue _FindLocal(string name, ICorDebugILFrame ilframe, ISymUnmanagedScope unmScope, uint ip) { int varcount; unmScope.GetLocalCount(out varcount); ISymUnmanagedVariable[] vars = new ISymUnmanagedVariable[varcount]; unmScope.GetLocals(varcount, out varcount, vars); for (int iv = 0; iv < varcount; iv++) { ISymUnmanagedVariable var = vars[iv]; string varname; { int namelen; var.GetName(0, out namelen, null); StringBuilder sbName = new StringBuilder(namelen); var.GetName(sbName.Capacity, out namelen, sbName); namelen--; // Remove nul. sbName.Length = namelen; varname = sbName.ToString(); } if (name == varname) { int field1; var.GetAddressField1(out field1); ICorDebugValue pvalue; ilframe.GetLocalVariable((uint)field1, out pvalue); return pvalue; } } int cChildren; unmScope.GetChildren(0, out cChildren, null); ISymUnmanagedScope[] children = new ISymUnmanagedScope[cChildren]; unmScope.GetChildren(children.Length, out cChildren, children); for (int ic = 0; ic < cChildren; ic++) { ICorDebugValue pvalue = _FindLocal(name, ilframe, children[ic], ip); if (null != pvalue) { return pvalue; } } return null; }
static void _PrintLocals(ICorDebugILFrame ilframe, ISymUnmanagedScope unmScope, uint ip, System.IO.TextWriter writer) { int varcount; unmScope.GetLocalCount(out varcount); ISymUnmanagedVariable[] vars = new ISymUnmanagedVariable[varcount]; unmScope.GetLocals(varcount, out varcount, vars); for (int iv = 0; iv < varcount; iv++) { ISymUnmanagedVariable var = vars[iv]; string varname; { int namelen; var.GetName(0, out namelen, null); StringBuilder sbName = new StringBuilder(namelen); var.GetName(sbName.Capacity, out namelen, sbName); namelen--; // Remove nul. sbName.Length = namelen; varname = sbName.ToString(); } string valstr; { int field1; var.GetAddressField1(out field1); ICorDebugValue pvalue; ilframe.GetLocalVariable((uint)field1, out pvalue); valstr = ToString(pvalue); } writer.WriteLine("{0}={1}", varname, valstr); } int cChildren; unmScope.GetChildren(0, out cChildren, null); ISymUnmanagedScope[] children = new ISymUnmanagedScope[cChildren]; unmScope.GetChildren(children.Length, out cChildren, children); for (int ic = 0; ic < cChildren; ic++) { _PrintLocals(ilframe, children[ic], ip, writer); } }
internal void GetLocalSourceNames(ISymUnmanagedScope/*!*/ scope, Hashtable/*!*/ localSourceNames) { uint numLocals = scope.GetLocalCount(); IntPtr[] localPtrs = new IntPtr[numLocals]; scope.GetLocals((uint)localPtrs.Length, out numLocals, localPtrs); char[] nameBuffer = new char[100]; uint nameLen; for (int i = 0; i < numLocals; i++) { ISymUnmanagedVariable local = (ISymUnmanagedVariable)System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(localPtrs[i], typeof(ISymUnmanagedVariable)); if (local != null) { local.GetName((uint)nameBuffer.Length, out nameLen, nameBuffer); int localIndex = (int)local.GetAddressField1(); localSourceNames[localIndex] = new String(nameBuffer, 0, (int)nameLen - 1); System.Runtime.InteropServices.Marshal.ReleaseComObject(local); } System.Runtime.InteropServices.Marshal.Release(localPtrs[i]); } IntPtr[] subscopes = new IntPtr[100]; uint numScopes; scope.GetChildren((uint)subscopes.Length, out numScopes, subscopes); for (int i = 0; i < numScopes; i++) { ISymUnmanagedScope subscope = (ISymUnmanagedScope)System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(subscopes[i], typeof(ISymUnmanagedScope)); if (subscope != null) { this.GetLocalSourceNames(subscope, localSourceNames); System.Runtime.InteropServices.Marshal.ReleaseComObject(subscope); } System.Runtime.InteropServices.Marshal.Release(subscopes[i]); //TODO: need to figure out how map these scope to blocks and set HasLocals on those blocks } }
List<DebugLocalVariableInfo> GetLocalVariablesInScope(ISymUnmanagedScope symScope) { List<DebugLocalVariableInfo> vars = new List<DebugLocalVariableInfo>(); foreach (ISymUnmanagedVariable symVar in symScope.GetLocals()) { ISymUnmanagedVariable symVarCopy = symVar; var locVarSig = new DebugSignatureReader().ReadTypeSignature(symVar.GetSignature()); DebugType locVarType = DebugType.CreateFromSignature(this.DebugModule, locVarSig, declaringType); // Compiler generated? // NB: Display class does not have the compiler-generated flag if ((symVar.GetAttributes() & 1) == 1 || symVar.GetName().StartsWith("CS$")) { // Get display class from local variable if (locVarType.IsDisplayClass) { AddCapturedLocalVariables( vars, (int)symScope.GetStartOffset(), (int)symScope.GetEndOffset(), delegate(StackFrame context) { return GetLocalVariableValue(context, symVarCopy); }, locVarType ); } } else { DebugLocalVariableInfo locVar = new DebugLocalVariableInfo( symVar.GetName(), (int)symVar.GetAddressField1(), // symVar also has Get*Offset methods, but the are not implemented (int)symScope.GetStartOffset(), (int)symScope.GetEndOffset(), locVarType, delegate(StackFrame context) { return GetLocalVariableValue(context, symVarCopy); } ); vars.Add(locVar); } } foreach(ISymUnmanagedScope childScope in symScope.GetChildren()) { vars.AddRange(GetLocalVariablesInScope(childScope)); } return vars; }
public int GetLocals(int cLocals, out int pcLocals, ISymUnmanagedVariable[] locals) { return(_scope.GetLocals(cLocals, out pcLocals, locals)); }
public static ISymUnmanagedVariable[] GetAndValidateVariables(ISymUnmanagedScope scope, int expectedCount) { int count, count2, count3; Assert.Equal(HResult.S_OK, scope.GetLocalCount(out count)); Assert.Equal(expectedCount, count); Assert.Equal(HResult.S_OK, scope.GetLocals(0, out count2, null)); Assert.Equal(expectedCount, count2); var variables = new ISymUnmanagedVariable[count]; Assert.Equal(HResult.S_OK, scope.GetLocals(count, out count3, variables)); Assert.Equal(count, count3); return variables; }
// // Gather the local details in a scope and then recurse to child scopes // private void ProbeScopeForLocals(List<ILLocalVariable> variables, ISymUnmanagedScope scope) { int localCount; ThrowExceptionForHR(scope.GetLocalCount(out localCount)); ISymUnmanagedVariable[] locals = new ISymUnmanagedVariable[localCount]; ThrowExceptionForHR(scope.GetLocals(localCount, out localCount, locals)); for (int i = 0; i < localCount; i++) { var local = locals[i]; int slot; ThrowExceptionForHR(local.GetAddressField1(out slot)); int nameLength; ThrowExceptionForHR(local.GetName(0, out nameLength, null)); // nameLength includes terminating '\0' char[] nameBuffer = new char[nameLength]; ThrowExceptionForHR(local.GetName(nameLength, out nameLength, nameBuffer)); int attributes; ThrowExceptionForHR(local.GetAttributes(out attributes)); variables.Add(new ILLocalVariable() { Slot = slot, Name = new String(nameBuffer, 0, nameLength - 1), CompilerGenerated = (attributes & 0x1) != 0 }); } int childrenCount; ThrowExceptionForHR(scope.GetChildren(0, out childrenCount, null)); ISymUnmanagedScope[] children = new ISymUnmanagedScope[childrenCount]; ThrowExceptionForHR(scope.GetChildren(childrenCount, out childrenCount, children)); for (int i = 0; i < childrenCount; i++) { ProbeScopeForLocals(variables, children[i]); } }
private void WriteLocalsHelper(ISymUnmanagedScope scope, Dictionary <int, ImmutableArray <string> > slotNames, bool includeChildScopes) { foreach (ISymUnmanagedVariable l in scope.GetLocals()) { writer.WriteStartElement("local"); { writer.WriteAttributeString("name", l.GetName()); // Each local maps to a "IL Index" or "slot" number. // The index is not necessarily unique. Several locals may refer to the same slot. // It just means that the same local is known under different names inside the same or different scopes. // This index is what you pass to ICorDebugILFrame::GetLocalVariable() to get // a specific local variable. // 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. int slot = l.GetSlot(); writer.WriteAttributeString("il_index", CultureInvariantToString(slot)); bool reusingSlot = false; // collect slot names so that we can verify ISymUnmanagedReader APIs if (slotNames != null) { ImmutableArray <string> existingNames; if (slotNames.TryGetValue(slot, out existingNames)) { slotNames[slot] = existingNames.Add(l.GetName()); reusingSlot = true; } else { slotNames.Add(slot, ImmutableArray.Create(l.GetName())); } } // Provide scope range writer.WriteAttributeString("il_start", AsILOffset(scope.GetStartOffset())); writer.WriteAttributeString("il_end", AsILOffset(scope.GetEndOffset())); writer.WriteAttributeString("attributes", l.GetAttributes().ToString()); if (reusingSlot) { writer.WriteAttributeString("reusingslot", reusingSlot.ToString(CultureInfo.InvariantCulture)); } } writer.WriteEndElement(); // </local> } foreach (ISymUnmanagedConstant c in scope.GetConstants()) { // Note: We can retrieve constant tokens by saving it into signature blob // in our implementation of IMetadataImport.GetSigFromToken. writer.WriteStartElement("constant"); { writer.WriteAttributeString("name", c.GetName()); object value = c.GetValue(); string typeName = value.GetType().Name; // certain Unicode characters will give Xml writers fits...in order to avoid this, we'll replace // problematic characters/sequences with their hexadecimal equivalents, like U+0000, etc... var chars = value as string; if (chars != null) { PooledStringBuilder pooled = PooledStringBuilder.GetInstance(); var valueWithPlaceholders = pooled.Builder; foreach (var ch in chars) { // if we end up with more, we can add them here if (0 == (int)ch) { valueWithPlaceholders.AppendFormat("U+{0:X4}", (int)ch); } else { valueWithPlaceholders.Append(ch); } } if (valueWithPlaceholders.Length > chars.Length) { value = valueWithPlaceholders.ToString(); } pooled.Free(); } writer.WriteAttributeString("value", value.ToString()); writer.WriteAttributeString("type", typeName); } writer.WriteEndElement(); // </constant> } if (includeChildScopes) { foreach (ISymUnmanagedScope childScope in scope.GetScopes()) { WriteLocalsHelper(childScope, slotNames, includeChildScopes); } } }
private void WriteLocalsHelper(ISymUnmanagedScope scope, Dictionary<int, ImmutableArray<string>> slotNames, bool includeChildScopes) { foreach (ISymUnmanagedVariable l in scope.GetLocals()) { writer.WriteStartElement("local"); { writer.WriteAttributeString("name", l.GetName()); // Each local maps to a "IL Index" or "slot" number. // The index is not necessarily unique. Several locals may refer to the same slot. // It just means that the same local is known under different names inside the same or different scopes. // This index is what you pass to ICorDebugILFrame::GetLocalVariable() to get // a specific local variable. // 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. int slot = l.GetSlot(); writer.WriteAttributeString("il_index", CultureInvariantToString(slot)); bool reusingSlot = false; // collect slot names so that we can verify ISymUnmanagedReader APIs if (slotNames != null) { ImmutableArray<string> existingNames; if (slotNames.TryGetValue(slot, out existingNames)) { slotNames[slot] = existingNames.Add(l.GetName()); reusingSlot = true; } else { slotNames.Add(slot, ImmutableArray.Create(l.GetName())); } } // Provide scope range writer.WriteAttributeString("il_start", AsILOffset(scope.GetStartOffset())); writer.WriteAttributeString("il_end", AsILOffset(scope.GetEndOffset())); writer.WriteAttributeString("attributes", l.GetAttributes().ToString()); if (reusingSlot) { writer.WriteAttributeString("reusingslot", reusingSlot.ToString(CultureInfo.InvariantCulture)); } } writer.WriteEndElement(); // </local> } foreach (ISymUnmanagedConstant c in scope.GetConstants()) { // Note: We can retrieve constant tokens by saving it into signature blob // in our implementation of IMetadataImport.GetSigFromToken. writer.WriteStartElement("constant"); { writer.WriteAttributeString("name", c.GetName()); object value = c.GetValue(); string typeName = value.GetType().Name; // certain Unicode characters will give Xml writers fits...in order to avoid this, we'll replace // problematic characters/sequences with their hexadecimal equivalents, like U+0000, etc... var chars = value as string; if (chars != null) { PooledStringBuilder pooled = PooledStringBuilder.GetInstance(); var valueWithPlaceholders = pooled.Builder; foreach (var ch in chars) { // if we end up with more, we can add them here if (0 == (int)ch) { valueWithPlaceholders.AppendFormat("U+{0:X4}", (int)ch); } else { valueWithPlaceholders.Append(ch); } } if (valueWithPlaceholders.Length > chars.Length) { value = valueWithPlaceholders.ToString(); } pooled.Free(); } writer.WriteAttributeString("value", value.ToString()); writer.WriteAttributeString("type", typeName); } writer.WriteEndElement(); // </constant> } if (includeChildScopes) { foreach (ISymUnmanagedScope childScope in scope.GetScopes()) { WriteLocalsHelper(childScope, slotNames, includeChildScopes); } } }