From 1f4dd33f530b924d76174a9d60e710cab42e31fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Sun, 30 Aug 2009 08:54:41 +0000 Subject: [PATCH] More flexible API for local variables; Get type of local variable; Generalized getting of type/method attributes git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4825 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/Control/StackFrame.cs | 26 +--- .../Src/Expressions/ExpressionEvaluator.cs | 5 +- .../Interop/CorSym/ISymUnmanagedVariable.cs | 4 +- .../Project/Src/Metadata/DebugType.cs | 16 +++ .../Project/Src/Metadata/MethodInfo.cs | 134 ++++++++++++++---- .../Mono.Cecil.Signatures/SignatureReader.cs | 8 +- .../CorDebug/ICorDebugGenericValue.cs | 1 + .../Wrappers/CorSym/ISymUnmanagedVariable.cs | 16 +++ 8 files changed, 154 insertions(+), 56 deletions(-) diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs index 22075a5f4b..5945b4e3ac 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs @@ -376,31 +376,15 @@ namespace Debugger #endregion - /// Returns value of give local variable - public Value GetLocalVariableValue(ISymUnmanagedVariable symVar) - { - return new Value(this.AppDomain, new IdentifierExpression(symVar.Name), GetLocalVariableCorValue(symVar)); - } - - ICorDebugValue GetLocalVariableCorValue(ISymUnmanagedVariable symVar) - { - try { - return CorILFrame.GetLocalVariable((uint)symVar.AddressField1); - } catch (COMException e) { - if ((uint)e.ErrorCode == 0x80131304) throw new GetValueException("Unavailable in optimized code"); - throw; - } - } - #region Convenience methods /// Get local variable with given name /// Null if not found public Value GetLocalVariableValue(string name) { - foreach(ISymUnmanagedVariable symVar in this.MethodInfo.LocalVariables) { - if (symVar.Name == name) { - return GetLocalVariableValue(symVar); + foreach(LocalVariableInfo locVar in this.MethodInfo.LocalVariables) { + if (locVar.Name == name) { + return locVar.GetValue(this); } } return null; @@ -410,8 +394,8 @@ namespace Debugger public List GetLocalVariableValues() { List values = new List(); - foreach(ISymUnmanagedVariable symVar in this.MethodInfo.LocalVariables) { - values.Add(GetLocalVariableValue(symVar)); + foreach(LocalVariableInfo locVar in this.MethodInfo.LocalVariables) { + values.Add(locVar.GetValue(this)); } return values; } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs index 4187d5af26..12b2eec024 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs @@ -115,7 +115,8 @@ namespace Debugger val = (Value)expression.AcceptVisitor(this, null); if (val != null && permRef) val = val.GetPermanentReference(); - } catch (GetValueException) { + } catch (GetValueException e) { + e.Expression = expression; throw; } catch (NotImplementedException e) { throw new GetValueException(expression, "Language feature not implemented: " + e.Message); @@ -125,7 +126,7 @@ namespace Debugger } if (val != null && val.IsInvalid) - throw new DebuggerException("Expression is invalid right after evaluation"); + throw new DebuggerException("Expression \"" + expression.PrettyPrint() + "\" is invalid right after evaluation"); // Add the result to cache context.Process.CachedExpressions[expression] = val; diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Interop/CorSym/ISymUnmanagedVariable.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Interop/CorSym/ISymUnmanagedVariable.cs index b310352a77..f86c6cd408 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Interop/CorSym/ISymUnmanagedVariable.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Interop/CorSym/ISymUnmanagedVariable.cs @@ -17,11 +17,11 @@ namespace Debugger.Interop.CorSym public interface ISymUnmanagedVariable { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] - void GetName([In] uint cchName, out uint pcchName, [Out] IntPtr szName); + void GetName([In] uint cchName, out uint pcchName, [In] IntPtr szName); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] uint GetAttributes(); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] - void GetSignature([In] uint cSig, out uint pcSig, [Out] IntPtr sig); + void GetSignature([In] uint cSig, out uint pcSig, [In] IntPtr sig); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] uint GetAddressKind(); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs index 9b786928b2..5c4f907f8f 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs @@ -721,6 +721,22 @@ namespace Debugger.MetaData return (GetMembers(bindingFlags).Count > 0); } + public bool IsCompilerGenerated { + get { + if (this.IsClass || this.IsValueType) { + return MethodInfo.HasAnyAttribute(this.Module.MetaData, this.Token, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)); + } else { + return false; + } + } + } + + public bool IsDisplayClass { + get { + return this.IsCompilerGenerated && this.Name.Contains("DisplayClass"); + } + } + public override string ToString() { return string.Format("{0}", this.FullName); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs index 1da75c1d19..5f60c7e633 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs @@ -5,13 +5,14 @@ // $Revision$ // -using ICSharpCode.NRefactory.Ast; using System; using System.Collections.Generic; using Debugger.Wrappers.CorDebug; using Debugger.Wrappers.CorSym; using Debugger.Wrappers.MetaData; +using ICSharpCode.NRefactory.Ast; using Mono.Cecil.Signatures; +using System.Runtime.InteropServices; namespace Debugger.MetaData { @@ -311,32 +312,42 @@ namespace Debugger.MetaData get { if (hasDebuggerAttributeCache.HasValue) return hasDebuggerAttributeCache.Value; - MetaDataImport metaData = this.Module.MetaData; - hasDebuggerAttributeCache = false; - // Look on the method - foreach(CustomAttributeProps ca in metaData.EnumCustomAttributeProps(methodProps.Token, 0)) { + hasDebuggerAttributeCache = + // Look on the method + HasAnyAttribute(this.Module.MetaData, methodProps.Token, + typeof(System.Diagnostics.DebuggerStepThroughAttribute), + typeof(System.Diagnostics.DebuggerNonUserCodeAttribute), + typeof(System.Diagnostics.DebuggerHiddenAttribute)) + || + // Look on the type + HasAnyAttribute(this.Module.MetaData, this.DeclaringType.Token, + typeof(System.Diagnostics.DebuggerStepThroughAttribute), + typeof(System.Diagnostics.DebuggerNonUserCodeAttribute), + typeof(System.Diagnostics.DebuggerHiddenAttribute)); + return hasDebuggerAttributeCache.Value; + } + } + + internal static bool HasAnyAttribute(MetaDataImport metaData, uint token, params Type[] wantedAttrTypes) + { + foreach(CustomAttributeProps ca in metaData.EnumCustomAttributeProps(token, 0)) { + CorTokenType tkType = (CorTokenType)(ca.Type & 0xFF000000); + string attributeName; + if (tkType == CorTokenType.MemberRef) { MemberRefProps constructorMethod = metaData.GetMemberRefProps(ca.Type); - TypeRefProps attributeType = metaData.GetTypeRefProps(constructorMethod.DeclaringType); - if (attributeType.Name == "System.Diagnostics.DebuggerStepThroughAttribute" || - attributeType.Name == "System.Diagnostics.DebuggerNonUserCodeAttribute" || - attributeType.Name == "System.Diagnostics.DebuggerHiddenAttribute") - { - hasDebuggerAttributeCache = true; - } + attributeName = metaData.GetTypeRefProps(constructorMethod.DeclaringType).Name; + } else if (tkType == CorTokenType.MethodDef) { + MethodProps constructorMethod = metaData.GetMethodProps(ca.Type); + attributeName = metaData.GetTypeDefProps(constructorMethod.ClassToken).Name; + } else { + throw new DebuggerException("Not expected: " + tkType); } - // Look on the type - foreach(CustomAttributeProps ca in metaData.EnumCustomAttributeProps(this.DeclaringType.Token, 0)) { - MemberRefProps constructorMethod = metaData.GetMemberRefProps(ca.Type); - TypeRefProps attributeType = metaData.GetTypeRefProps(constructorMethod.DeclaringType); - if (attributeType.Name == "System.Diagnostics.DebuggerStepThroughAttribute" || - attributeType.Name == "System.Diagnostics.DebuggerNonUserCodeAttribute" || - attributeType.Name == "System.Diagnostics.DebuggerHiddenAttribute") - { - hasDebuggerAttributeCache = true; - } + foreach(Type wantedAttrType in wantedAttrTypes) { + if (attributeName == wantedAttrType.FullName) + return true; } - return hasDebuggerAttributeCache.Value; } + return false; } internal void MarkAsNonUserCode() @@ -413,19 +424,19 @@ namespace Debugger.MetaData } [Debugger.Tests.Ignore] - public List LocalVariables { + public List LocalVariables { get { if (this.SymMethod != null) { // TODO: Is this needed? return GetLocalVariablesInScope(this.SymMethod.RootScope); } else { - return new List(); + return new List(); } } } public string[] LocalVariableNames { get { - List vars = LocalVariables; + List vars = this.LocalVariables; List names = new List(); for(int i = 0; i < vars.Count; i++) { names.Add(vars[i].Name); @@ -435,12 +446,29 @@ namespace Debugger.MetaData } } - List GetLocalVariablesInScope(ISymUnmanagedScope symScope) + List GetLocalVariablesInScope(ISymUnmanagedScope symScope) { - List vars = new List(); + List vars = new List(); foreach (ISymUnmanagedVariable symVar in symScope.Locals) { - if (!symVar.Name.StartsWith("CS$")) { // TODO: Generalize - vars.Add(symVar); + int start; + SignatureReader sigReader = new SignatureReader(symVar.Signature); + LocalVarSig.LocalVariable locVarSig = sigReader.ReadLocalVariable(sigReader.Blob, 0, out start); + DebugType type = DebugType.CreateFromSignature(this.Module, locVarSig.Type, this.DeclaringType); + // Compiler generated? + if ((symVar.Attributes & 1) == 1) { + if (type.IsDisplayClass) { + + } + } else { + ISymUnmanagedVariable symVarCopy = symVar; + LocalVariableInfo locVar = new LocalVariableInfo( + symVar.Name, + type, + delegate(StackFrame context) { + return GetLocalVariableValue(context, symVarCopy); + } + ); + vars.Add(locVar); } } foreach(ISymUnmanagedScope childScope in symScope.Children) { @@ -448,5 +476,51 @@ namespace Debugger.MetaData } return vars; } + + static Value GetLocalVariableValue(StackFrame context, ISymUnmanagedVariable symVar) + { + ICorDebugValue corVal; + try { + corVal = context.CorILFrame.GetLocalVariable((uint)symVar.AddressField1); + } catch (COMException e) { + if ((uint)e.ErrorCode == 0x80131304) throw new GetValueException("Unavailable in optimized code"); + throw; + } + return new Value(context.AppDomain, new IdentifierExpression(symVar.Name), corVal); + } + } + + public class LocalVariableInfo + { + public delegate Value LocalVariableValueGetter(StackFrame context); + + string name; + DebugType type; + LocalVariableValueGetter getter; + + public string Name { + get { return name; } + } + + public DebugType Type { + get { return type; } + } + + public LocalVariableInfo(string name, DebugType type, LocalVariableValueGetter getter) + { + this.name = name; + this.type = type; + this.getter = getter; + } + + public Value GetValue(StackFrame context) + { + return getter(context); + } + + public override string ToString() + { + return this.Type.ToString() + " " + this.Name; + } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Mono.Cecil/Mono.Cecil.Signatures/SignatureReader.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Mono.Cecil/Mono.Cecil.Signatures/SignatureReader.cs index 709634c534..2e90b28d4e 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Mono.Cecil/Mono.Cecil.Signatures/SignatureReader.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Mono.Cecil/Mono.Cecil.Signatures/SignatureReader.cs @@ -41,6 +41,12 @@ namespace Mono.Cecil.Signatures { byte [] m_blobData; IDictionary m_signatures; + public byte[] Blob { + get { + return m_blobData; + } + } + public SignatureReader (byte [] blobData) { m_blobData = blobData; @@ -325,7 +331,7 @@ namespace Mono.Cecil.Signatures { return types; } - LocalVarSig.LocalVariable ReadLocalVariable (byte [] data, int pos, out int start) + public LocalVarSig.LocalVariable ReadLocalVariable (byte [] data, int pos, out int start) { start = pos; LocalVarSig.LocalVariable lv = new LocalVarSig.LocalVariable (); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorDebug/ICorDebugGenericValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorDebug/ICorDebugGenericValue.cs index 86b55de632..ab02841887 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorDebug/ICorDebugGenericValue.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorDebug/ICorDebugGenericValue.cs @@ -16,6 +16,7 @@ namespace Debugger.Wrappers.CorDebug { public unsafe Byte[] RawValue { get { + // TODO: Unset fixing insead Byte[] retValue = new Byte[(int)Size]; IntPtr pValue = Marshal.AllocHGlobal(retValue.Length); GetValue(pValue); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorSym/ISymUnmanagedVariable.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorSym/ISymUnmanagedVariable.cs index f1ad92cfd0..41fe452914 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorSym/ISymUnmanagedVariable.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorSym/ISymUnmanagedVariable.cs @@ -18,6 +18,22 @@ namespace Debugger.Wrappers.CorSym return Util.GetString(GetName); } } + + const int defaultSigSize = 8; + + public unsafe byte[] Signature { + get { + byte[] sig = new byte[defaultSigSize]; + uint acualSize; + fixed(byte* pSig = sig) + this.GetSignature((uint)sig.Length, out acualSize, new IntPtr(pSig)); + Array.Resize(ref sig, (int)acualSize); + if (acualSize > defaultSigSize) + fixed(byte* pSig = sig) + this.GetSignature((uint)sig.Length, out acualSize, new IntPtr(pSig)); + return sig; + } + } } }