diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs
index 1a248e4772..0dca2c514f 100644
--- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs
@@ -88,7 +88,7 @@ namespace ICSharpCode.SharpDevelop.Services
image = DebuggerIcons.GetImage(variable);
this[1].Text = ""; // Icon
this[2].Text = variable.Name;
- if (ShowValuesInHexadecimal && variable.ValueProxy is PrimitiveValue && variable.ValueProxy.IsInteger) {
+ if (ShowValuesInHexadecimal && variable.ValueProxy is PrimitiveValue && variable.ValueProxy.TheValue.IsInteger) {
this[3].Text = String.Format("0x{0:X}", (variable.ValueProxy as PrimitiveValue).Primitive);
} else {
this[3].Text = variable.ValueProxy.AsString;
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
index 03d7103334..f7cc1b6ac2 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
@@ -377,18 +377,18 @@
-
-
+
+
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs
index d2aeaa0120..449ddb2d55 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs
@@ -23,7 +23,7 @@ namespace Debugger
protected ICorDebugArrayValue CorArrayValue {
get {
- return this.CorValue.CastTo();
+ return TheValue.CorValue.CastTo();
}
}
@@ -35,7 +35,7 @@ namespace Debugger
public string ElementsType {
get {
- return CorTypeToString(corElementType);
+ return Value.CorTypeToString(corElementType);
}
}
@@ -72,7 +72,7 @@ namespace Debugger
bool IsCorValueCompatible {
get {
- ArrayValue freshValue = this.FreshValue as ArrayValue;
+ ArrayValue freshValue = TheValue.ValueProxy as ArrayValue;
return freshValue != null &&
freshValue.ElementsType == this.ElementsType &&
freshValue.Lenght == this.Lenght &&
@@ -119,9 +119,9 @@ namespace Debugger
elementName,
indices,
new Value(
- Process,
- new IExpirable[] {this.Value},
- new IMutable[] {this.Value},
+ TheValue.Process,
+ new IExpirable[] {this.TheValue},
+ new IMutable[] {this.TheValue},
delegate { return GetCorValueOfItem(indices); }
)
);
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs
index 803cb3a6e8..e0fb81ad0d 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs
@@ -17,12 +17,9 @@ namespace Debugger
}
}
- public override string Type
- {
- get
- {
- switch (CorType)
- {
+ public override string Type {
+ get {
+ switch (TheValue.CorType) {
case CorElementType.SZARRAY:
case CorElementType.ARRAY: return typeof(System.Array).ToString();
case CorElementType.OBJECT: return typeof(System.Object).ToString();
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs
index d81e27595b..9b1e4f9e7c 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs
@@ -68,20 +68,20 @@ namespace Debugger
internal ObjectValue(Value @value):base(@value)
{
- topClass = new ObjectValueClass(this, this.CorValue.As().Class);
+ topClass = new ObjectValueClass(this, TheValue.CorValue.As().Class);
Module module = GetClass("System.Object").Module;
ICorDebugFunction corFunction = module.GetMethod("System.Object", "ToString", 0);
- toStringText = new CallFunctionEval(this.Process,
- new IExpirable[] {this.Value},
- new IMutable[] {this.Value},
+ toStringText = new CallFunctionEval(TheValue.Process,
+ new IExpirable[] {this.TheValue},
+ new IMutable[] {this.TheValue},
corFunction,
- this.Value,
+ TheValue,
new Value[] {});
}
internal bool IsCorValueCompatible {
get {
- ObjectValue freshValue = this.FreshValue as ObjectValue;
+ ObjectValue freshValue = TheValue.ValueProxy as ObjectValue;
return freshValue != null &&
topClass.Module == freshValue.TopClass.Module &&
topClass.ClassToken == freshValue.TopClass.ClassToken;
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs
index 58bf45c827..e91248abf5 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs
@@ -24,7 +24,7 @@ namespace Debugger
ICorDebugObjectValue CorObjectValue {
get {
- return objectValue.CorValue.As();
+ return objectValue.TheValue.CorValue.As();
}
}
@@ -60,7 +60,7 @@ namespace Debugger
public ObjectValueClass(ObjectValue objectValue, ICorDebugClass corClass)
{
- this.process = objectValue.Process;
+ this.process = objectValue.TheValue.Process;
this.objectValue = objectValue;
this.module = process.GetModule(corClass.Module);
this.corClass = corClass;
@@ -139,8 +139,8 @@ namespace Debugger
(field.IsPublic ? ObjectMember.Flags.Public : ObjectMember.Flags.None),
new Value(
process,
- new IExpirable[] {this.objectValue.Value},
- new IMutable[] {this.objectValue.Value},
+ new IExpirable[] {this.objectValue.TheValue},
+ new IMutable[] {this.objectValue.TheValue},
delegate { return GetCorValueOfField(field); }
)
);
@@ -186,10 +186,10 @@ namespace Debugger
flags,
new CallFunctionEval(
process,
- new IExpirable[] {this.objectValue.Value},
+ new IExpirable[] {this.objectValue.TheValue},
new IMutable[] {process.DebugeeState},
Module.CorModule.GetFunctionFromToken(method.Token),
- method.IsStatic ? null : this.objectValue.Value, // this
+ method.IsStatic ? null : this.objectValue.TheValue, // this
new Value[] {}
)
); // args
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs
index 00bf90dc99..a5cc79698b 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs
@@ -25,10 +25,10 @@ namespace Debugger
public object Primitive {
get {
- if (CorType == CorElementType.STRING) {
- return (CorValue.CastTo()).String;
+ if (TheValue.CorType == CorElementType.STRING) {
+ return (TheValue.CorValue.CastTo()).String;
} else {
- return (CorValue.CastTo()).Value;
+ return (TheValue.CorValue.CastTo()).Value;
}
}
set {
@@ -40,12 +40,12 @@ namespace Debugger
throw new NotSupportedException("Can not convert " + value.GetType().ToString() + " to " + ManagedType.ToString());
}
- if (CorType == CorElementType.STRING) {
+ if (TheValue.CorType == CorElementType.STRING) {
throw new NotSupportedException();
} else {
- (CorValue.CastTo()).Value = newValue;
+ (TheValue.CorValue.CastTo()).Value = newValue;
}
- this.Value.NotifyChange();
+ TheValue.NotifyChange();
}
}
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs
index 257fc9c04f..8c8fcabb8d 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs
@@ -1,124 +1,407 @@
-//
+//
//
//
-//
+//
// $Revision$
//
using System;
+using System.Collections.Generic;
+
using Debugger.Wrappers.CorDebug;
namespace Debugger
{
- public abstract class ValueProxy: RemotingObjectBase
+ ///
+ /// Delegate that is used to get value. This delegate may be called at any time and should never return null.
+ ///
+ delegate ICorDebugValue CorValueGetter();
+
+ ///
+ /// Value is a container which holds data necessaty to obtain
+ /// the value of a given object even after continue. This level of
+ /// abstraction is necessary because the type of a value can change
+ /// (eg for local variable of type object)
+ ///
+ /// Expiration: Once value expires it can not be used anymore.
+ /// Expiration is permanet - once value expires it stays expired.
+ /// Value expires when any object specified in constructor expires
+ /// or when process exits.
+ ///
+ /// Mutation: As long as any dependecy does not mutate the last
+ /// obteined value is still considered up to date. (If continue is
+ /// called and internal value is neutred new copy will be obatined)
+ ///
+ public class Value: IExpirable, IMutable
{
- Value val;
+ protected Process process;
+
+ CorValueGetter corValueGetter;
+ IMutable[] mutateDependencies;
+
+ protected ValueProxy currentValue;
+ protected ICorDebugValue currentCorValue;
+ protected PauseSession currentCorValuePauseSession;
+
+ bool isExpired = false;
+
+ public event EventHandler Expired;
+ public event EventHandler Changed;
public Process Process {
get {
- return val.Process;
+ return process;
}
}
- public Value Value {
+ public ICorDebugValue CorValue {
get {
- return val;
+ return DereferenceUnbox(RawCorValue);
}
}
- internal ICorDebugValue CorValue {
+ internal CorElementType CorType {
get {
- return val.CorValue;
+ return GetCorType(this.CorValue);
}
}
- protected ValueProxy FreshValue {
- get {
- return val.ValueProxy;
+ internal static CorElementType GetCorType(ICorDebugValue corValue)
+ {
+ if (corValue == null) {
+ return (CorElementType)0;
}
+ return (CorElementType)corValue.Type;
}
- internal CorElementType CorType {
+ protected virtual ICorDebugValue RawCorValue {
get {
- return GetCorType(CorValue);
+ if (this.HasExpired) throw new CannotGetValueException("CorValue has expired");
+ if (currentCorValue == null || (currentCorValuePauseSession != process.PauseSession && !currentCorValue.Is())) {
+ currentCorValue = corValueGetter();
+ currentCorValuePauseSession = process.PauseSession;
+ }
+ return currentCorValue;
}
}
- public abstract string AsString {
- get;
- }
-
- public virtual string Type {
- get{
- return CorTypeToString(CorType);
- }
+ public ValueProxy ValueProxy {
+ get {
+ if (currentValue == null) {
+ try {
+ currentValue = CreateValue();
+ } catch (CannotGetValueException e) {
+ currentValue = new UnavailableValue(this, e.Message);
+ }
+ }
+ return currentValue;
+ }
}
- public virtual Type ManagedType {
+ public bool HasExpired {
get {
- return CorTypeToManagedType(CorType);
+ return isExpired;
}
}
- public bool MayHaveSubVariables {
+ public ICorDebugValue SoftReference {
get {
- #if DEBUG
- return true;
- #else
- return GetMayHaveSubVariables();
- #endif
+ if (this.HasExpired) throw new DebuggerException("CorValue has expired");
+
+ ICorDebugValue corValue = RawCorValue;
+ if (corValue != null && corValue.Is()) {
+ return corValue;
+ }
+ corValue = DereferenceUnbox(corValue);
+ if (corValue != null && corValue.Is()) {
+ return corValue.As().CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION).CastTo();
+ } else {
+ return corValue; // Value type - return value type
+ }
}
}
- protected abstract bool GetMayHaveSubVariables();
+ internal Value(Process process,
+ IExpirable[] expireDependencies,
+ IMutable[] mutateDependencies,
+ CorValueGetter corValueGetter)
+ {
+ this.process = process;
+
+ foreach(IExpirable exp in expireDependencies) {
+ AddExpireDependency(exp);
+ }
+ AddExpireDependency(process);
+
+ this.mutateDependencies = mutateDependencies;
+ if (!this.HasExpired) {
+ foreach(IMutable mut in mutateDependencies) {
+ AddMutateDependency(mut);
+ }
+ }
+
+ this.corValueGetter = corValueGetter;
+ }
- public VariableCollection SubVariables {
- get {
- VariableCollection subVars = GetSubVariables();
- #if DEBUG
- return new VariableCollection(subVars.Name,
- subVars.Value,
- Util.MergeLists(val.GetDebugInfo(), subVars.SubCollections).ToArray(),
- subVars.Items);
- #else
- return subVars;
- #endif
+ void AddExpireDependency(IExpirable dependency)
+ {
+ if (dependency.HasExpired) {
+ MakeExpired();
+ } else {
+ dependency.Expired += delegate { MakeExpired(); };
}
}
- protected virtual VariableCollection GetSubVariables()
+ void AddMutateDependency(IMutable dependency)
{
- return new VariableCollection(new Variable[] {});
+ dependency.Changed += DependencyChanged;
}
- public Variable this[string variableName] {
- get {
- foreach(Variable v in SubVariables) {
- if (v.Name == variableName) return v;
+ void MakeExpired()
+ {
+ if (!isExpired) {
+ isExpired = true;
+ OnExpired(new ValueEventArgs(this));
+ foreach(IMutable mut in mutateDependencies) {
+ mut.Changed -= DependencyChanged;
}
- throw new DebuggerException("Subvariable " + variableName + " does not exist");
}
}
- protected ValueProxy(Value @value)
+ void DependencyChanged(object sender, ProcessEventArgs e)
{
- if (@value == null) throw new ArgumentNullException("value");
- this.val = @value;
+ NotifyChange();
}
- public override string ToString()
+ protected virtual void ClearCurrentValue()
{
- return AsString;
+ currentValue = null;
+ currentCorValue = null;
+ currentCorValuePauseSession = null;
}
- internal static CorElementType GetCorType(ICorDebugValue corValue)
+ internal void NotifyChange()
+ {
+ ClearCurrentValue();
+ if (!isExpired) {
+ OnChanged(new ValueEventArgs(this));
+ }
+ }
+
+ protected virtual void OnChanged(ProcessEventArgs e)
+ {
+ if (Changed != null) {
+ Changed(this, e);
+ }
+ }
+
+ protected virtual void OnExpired(EventArgs e)
+ {
+ if (Expired != null) {
+ Expired(this, e);
+ }
+ }
+
+ internal static ICorDebugValue DereferenceUnbox(ICorDebugValue corValue)
{
+ // Method arguments can be passed 'by ref'
+ if (corValue.Type == (uint)CorElementType.BYREF) {
+ corValue = corValue.CastTo().Dereference();
+ }
+
+ // Pointers may be used in 'unsafe' code - CorElementType.PTR
+ // Classes need to be dereferenced
+ while (corValue.Is()) {
+ ICorDebugReferenceValue refValue = corValue.CastTo();
+ if (refValue.IsNull != 0) {
+ return null; // Reference is null
+ } else {
+ try {
+ corValue = refValue.Dereference();
+ // TODO: Investigate: Must not acutally be null
+ // eg. Assembly.AssemblyHandle See SD2-1117
+ if (corValue == null) return null; // Dereference() returned null
+ } catch {
+ return null; // Error during dereferencing
+ }
+ }
+ }
+
+ // Unbox value types
+ if (corValue.Is()) {
+ corValue = corValue.CastTo().Object.CastTo();
+ }
+
+ return corValue;
+ }
+
+ public enum ValueType {Null, Primitive, Array, Object, Unknown};
+
+ ValueType GetValueType()
+ {
+ ICorDebugValue corValue = this.CorValue;
+
if (corValue == null) {
- return (CorElementType)0;
+ return ValueType.Null;
+ }
+
+ switch(GetCorType(corValue)) {
+ case CorElementType.BOOLEAN:
+ case CorElementType.CHAR:
+ case CorElementType.I1:
+ case CorElementType.U1:
+ case CorElementType.I2:
+ case CorElementType.U2:
+ case CorElementType.I4:
+ case CorElementType.U4:
+ case CorElementType.I8:
+ case CorElementType.U8:
+ case CorElementType.R4:
+ case CorElementType.R8:
+ case CorElementType.I:
+ case CorElementType.U:
+ case CorElementType.STRING:
+ return ValueType.Primitive;
+
+ case CorElementType.ARRAY:
+ case CorElementType.SZARRAY: // Short-cut for single dimension zero lower bound array
+ return ValueType.Array;
+
+ case CorElementType.VALUETYPE:
+ case CorElementType.CLASS:
+ case CorElementType.OBJECT: // Short-cut for Class "System.Object"
+ return ValueType.Object;
+
+ default: // Unknown type
+ return ValueType.Unknown;
}
- return (CorElementType)corValue.Type;
}
-
+
+ ValueProxy CreateValue()
+ {
+ ICorDebugValue corValue = this.CorValue;
+
+ switch(GetValueType()) {
+ case ValueType.Null: return new NullValue(this);
+ case ValueType.Primitive: return new PrimitiveValue(this);
+ case ValueType.Array: return new ArrayValue(this);
+ case ValueType.Object: return new ObjectValue(this);
+ default: throw new CannotGetValueException("Unknown value type");
+ }
+ }
+
+ public bool SetValue(Value newValue)
+ {
+ ICorDebugValue corValue = this.RawCorValue;
+ ICorDebugValue newCorValue = newValue.RawCorValue;
+ if (newCorValue.Type == (uint)CorElementType.BYREF) {
+ newCorValue = newCorValue.As().Dereference();
+ }
+
+ if (corValue.Is()) {
+ if (newCorValue.Is()) {
+ ICorDebugClass corClass = newCorValue.As().Class;
+ ICorDebugValue box = Eval.NewObject(process, corClass).RawCorValue;
+ newCorValue = box;
+ }
+ corValue.CastTo().SetValue(newCorValue.CastTo().Value);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ ///
+ /// Returns true if the value is signed or unsigned integer of any size
+ ///
+ public bool IsInteger {
+ get {
+ CorElementType corType = CorType;
+ return corType == CorElementType.I1 ||
+ corType == CorElementType.U1 ||
+ corType == CorElementType.I2 ||
+ corType == CorElementType.U2 ||
+ corType == CorElementType.I4 ||
+ corType == CorElementType.U4 ||
+ corType == CorElementType.I8 ||
+ corType == CorElementType.U8 ||
+ corType == CorElementType.I ||
+ corType == CorElementType.U;
+ }
+ }
+
+ public VariableCollection GetDebugInfo()
+ {
+ return GetDebugInfo(this.RawCorValue);
+ }
+
+ public static VariableCollection GetDebugInfo(ICorDebugValue corValue)
+ {
+ List items = new List();
+
+ if (corValue.Is()) {
+ List more = new List();
+ more.Add(new VariableCollection("type", ((CorElementType)corValue.Type).ToString()));
+ more.Add(new VariableCollection("size", corValue.Size.ToString()));
+ more.Add(new VariableCollection("address", corValue.Address.ToString("X")));
+ items.Add(new VariableCollection("ICorDebugValue", "", more, null));
+ }
+ if (corValue.Is()) items.Add(new VariableCollection("ICorDebugValue2", "", null, null));
+ if (corValue.Is()) {
+ List more = new List();
+ try {
+ byte[] bytes = corValue.CastTo().RawValue;
+ for(int i = 0; i < bytes.Length; i += 8) {
+ string val = "";
+ for(int j = i; j < bytes.Length && j < i + 8; j++) {
+ val += bytes[j].ToString("X2") + " ";
+ }
+ more.Add(new VariableCollection("data" + i.ToString("X2"), val));
+ }
+ } catch (ArgumentException) {
+ more.Add(new VariableCollection("data", "N/A"));
+ }
+ items.Add(new VariableCollection("ICorDebugGenericValue", "", more, null));
+ }
+ if (corValue.Is()) {
+ List more = new List();
+ ICorDebugReferenceValue refValue = corValue.CastTo();
+ bool isNull = refValue.IsNull != 0;
+ more.Add(new VariableCollection("isNull", isNull.ToString()));
+ if (!isNull) {
+ more.Add(new VariableCollection("address", refValue.Value.ToString("X")));
+ if (refValue.Dereference() != null) {
+ VariableCollection deRef = GetDebugInfo(refValue.Dereference());
+ more.Add(new VariableCollection("dereferenced", deRef.Value, deRef.SubCollections, deRef.Items));
+ } else {
+ more.Add(new VariableCollection("dereferenced", "N/A", null, null));
+ }
+
+ }
+ items.Add(new VariableCollection("ICorDebugReferenceValue", "", more, null));
+ }
+ if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHeapValue", "", null, null));
+ if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHeapValue2", "", null, null));
+ if (corValue.Is()) {
+ List more = new List();
+ bool isValue = corValue.CastTo().IsValueClass != 0;
+ more.Add(new VariableCollection("isValue", isValue.ToString()));
+ items.Add(new VariableCollection("ICorDebugObjectValue", "", more, null));
+ }
+ if (corValue.Is()) items.Add(new VariableCollection("ICorDebugObjectValue2", "", null, null));
+ if (corValue.Is()) {
+ List more = new List();
+ VariableCollection unboxed = GetDebugInfo(corValue.CastTo().Object.CastTo());
+ more.Add(new VariableCollection("unboxed", unboxed.Value, unboxed.SubCollections, unboxed.Items));
+ items.Add(new VariableCollection("ICorDebugBoxValue", "", more, null));
+ }
+ if (corValue.Is()) items.Add(new VariableCollection("ICorDebugStringValue", "", null, null));
+ if (corValue.Is()) items.Add(new VariableCollection("ICorDebugArrayValue", "", null, null));
+ if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHandleValue", "", null, null));
+
+ return new VariableCollection("$debugInfo", ((CorElementType)corValue.Type).ToString(), items.ToArray(), null);
+ }
+
internal static System.Type CorTypeToManagedType(CorElementType corType)
{
switch(corType)
@@ -145,25 +428,6 @@ namespace Debugger
}
}
- ///
- /// Returns true if the value is signed or unsigned integer of any size
- ///
- public bool IsInteger {
- get {
- CorElementType corType = CorType;
- return corType == CorElementType.I1 ||
- corType == CorElementType.U1 ||
- corType == CorElementType.I2 ||
- corType == CorElementType.U2 ||
- corType == CorElementType.I4 ||
- corType == CorElementType.U4 ||
- corType == CorElementType.I8 ||
- corType == CorElementType.U8 ||
- corType == CorElementType.I ||
- corType == CorElementType.U;
- }
- }
-
internal static string CorTypeToString(CorElementType corType)
{
Type manType = CorTypeToManagedType(corType);
@@ -171,4 +435,12 @@ namespace Debugger
return manType.ToString();
}
}
+
+ class CannotGetValueException: System.Exception
+ {
+ public CannotGetValueException(string message):base(message)
+ {
+
+ }
+ }
}
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs
new file mode 100644
index 0000000000..da645106b5
--- /dev/null
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs
@@ -0,0 +1,93 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using Debugger.Wrappers.CorDebug;
+
+namespace Debugger
+{
+ ///
+ /// Provides more specific access
+ ///
+ public abstract class ValueProxy: RemotingObjectBase
+ {
+ Value val;
+
+ public Value TheValue {
+ get {
+ return val;
+ }
+ }
+
+ public abstract string AsString {
+ get;
+ }
+
+ public virtual string Type {
+ get{
+ return Value.CorTypeToString(TheValue.CorType);
+ }
+ }
+
+ public virtual Type ManagedType {
+ get {
+ return Value.CorTypeToManagedType(TheValue.CorType);
+ }
+ }
+
+ public bool MayHaveSubVariables {
+ get {
+ #if DEBUG
+ return true;
+ #else
+ return GetMayHaveSubVariables();
+ #endif
+ }
+ }
+
+ protected abstract bool GetMayHaveSubVariables();
+
+ public VariableCollection SubVariables {
+ get {
+ VariableCollection subVars = GetSubVariables();
+ #if DEBUG
+ return new VariableCollection(subVars.Name,
+ subVars.Value,
+ Util.MergeLists(val.GetDebugInfo(), subVars.SubCollections).ToArray(),
+ subVars.Items);
+ #else
+ return subVars;
+ #endif
+ }
+ }
+
+ protected virtual VariableCollection GetSubVariables()
+ {
+ return new VariableCollection(new Variable[] {});
+ }
+
+ public Variable this[string variableName] {
+ get {
+ foreach(Variable v in SubVariables) {
+ if (v.Name == variableName) return v;
+ }
+ throw new DebuggerException("Subvariable " + variableName + " does not exist");
+ }
+ }
+
+ protected ValueProxy(Value @value)
+ {
+ if (@value == null) throw new ArgumentNullException("value");
+ this.val = @value;
+ }
+
+ public override string ToString()
+ {
+ return AsString;
+ }
+ }
+}
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs
index 8f848d2fd5..0d18c1f3be 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs
@@ -1,7 +1,7 @@
-//
+//
//
//
-//
+//
// $Revision$
//
@@ -13,358 +13,79 @@ using Debugger.Wrappers.CorDebug;
namespace Debugger
{
///
- /// Delegate that is used to get value. This delegate may be called at any time and should never return null.
- ///
- delegate ICorDebugValue CorValueGetter();
-
- ///
- /// Value is a container which holds data necessaty to obtain
- /// the value of a given object even after continue. This level of
- /// abstraction is necessary because the type of a value can change
- /// (eg for local variable of type object)
- ///
- /// Value is a container for Variable which makes it possible to
- /// access specific properties of current value (eg array)
///
- /// Expiration: Once value expires it can not be used anymore.
- /// Expiration is permanet - once value expires it stays expired.
- /// Value expires when any object specified in constructor expires
- /// or when process exits.
- ///
- /// Mutation: As long as any dependecy does not mutate the last
- /// obteined value is still considered up to date. (If continue is
- /// called and internal value is neutred new copy will be obatined)
///
- public class Value: IExpirable, IMutable
+ public class Variable: IExpirable, IMutable
{
- protected Process process;
-
- CorValueGetter corValueGetter;
- IMutable[] mutateDependencies;
-
- protected ValueProxy currentValue;
- protected ICorDebugValue currentCorValue;
- protected PauseSession currentCorValuePauseSession;
-
- bool isExpired = false;
+ string name;
+ Value val;
+ bool hasExpired;
public event EventHandler Expired;
public event EventHandler Changed;
public Process Process {
get {
- return process;
+ return val.Process;
}
}
- public ICorDebugValue CorValue {
+ public string Name {
get {
- return DereferenceUnbox(RawCorValue);
+ return name;
}
}
- protected virtual ICorDebugValue RawCorValue {
+ public Value Value {
get {
- if (this.HasExpired) throw new CannotGetValueException("CorValue has expired");
- if (currentCorValue == null || (currentCorValuePauseSession != process.PauseSession && !currentCorValue.Is())) {
- currentCorValue = corValueGetter();
- currentCorValuePauseSession = process.PauseSession;
- }
- return currentCorValue;
+ return val;
}
}
public ValueProxy ValueProxy {
get {
- if (currentValue == null) {
- try {
- currentValue = CreateValue();
- } catch (CannotGetValueException e) {
- currentValue = new UnavailableValue(this, e.Message);
- }
- }
- return currentValue;
+ return val.ValueProxy;
}
}
public bool HasExpired {
get {
- return isExpired;
- }
- }
-
- public ICorDebugValue SoftReference {
- get {
- if (this.HasExpired) throw new DebuggerException("CorValue has expired");
-
- ICorDebugValue corValue = RawCorValue;
- if (corValue != null && corValue.Is()) {
- return corValue;
- }
- corValue = DereferenceUnbox(corValue);
- if (corValue != null && corValue.Is()) {
- return corValue.As().CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION).CastTo();
- } else {
- return corValue; // Value type - return value type
- }
+ return hasExpired;
}
}
- internal Value(Process process,
- IExpirable[] expireDependencies,
- IMutable[] mutateDependencies,
- CorValueGetter corValueGetter)
+ internal Variable(string name, Value @value)
{
- this.process = process;
+ if (@value == null) throw new ArgumentNullException("value");
- foreach(IExpirable exp in expireDependencies) {
- AddExpireDependency(exp);
- }
- AddExpireDependency(process);
+ this.name = name;
+ this.val = @value;
+ this.val.Expired += delegate(object sender, EventArgs e) { OnExpired(e); };
+ this.val.Changed += delegate(object sender, ProcessEventArgs e) { OnChanged(e); };
- this.mutateDependencies = mutateDependencies;
- if (!this.HasExpired) {
- foreach(IMutable mut in mutateDependencies) {
- AddMutateDependency(mut);
+ if (name.StartsWith("<") && name.Contains(">") && name != "") {
+ string middle = name.TrimStart('<').Split('>')[0]; // Get text between '<' and '>'
+ if (middle != "") {
+ this.name = middle;
}
}
-
- this.corValueGetter = corValueGetter;
}
- void AddExpireDependency(IExpirable dependency)
- {
- if (dependency.HasExpired) {
- MakeExpired();
- } else {
- dependency.Expired += delegate { MakeExpired(); };
- }
- }
-
- void AddMutateDependency(IMutable dependency)
- {
- dependency.Changed += DependencyChanged;
- }
-
- void MakeExpired()
+ protected virtual void OnExpired(EventArgs e)
{
- if (!isExpired) {
- isExpired = true;
- OnExpired(new ValueEventArgs(this));
- foreach(IMutable mut in mutateDependencies) {
- mut.Changed -= DependencyChanged;
+ if (!hasExpired) {
+ hasExpired = true;
+ if (Expired != null) {
+ Expired(this, e);
}
}
}
- void DependencyChanged(object sender, ProcessEventArgs e)
- {
- NotifyChange();
- }
-
- protected virtual void ClearCurrentValue()
- {
- currentValue = null;
- currentCorValue = null;
- currentCorValuePauseSession = null;
- }
-
- internal void NotifyChange()
- {
- ClearCurrentValue();
- if (!isExpired) {
- OnChanged(new ValueEventArgs(this));
- }
- }
-
protected virtual void OnChanged(ProcessEventArgs e)
{
if (Changed != null) {
Changed(this, e);
}
}
-
- protected virtual void OnExpired(EventArgs e)
- {
- if (Expired != null) {
- Expired(this, e);
- }
- }
-
- internal static ICorDebugValue DereferenceUnbox(ICorDebugValue corValue)
- {
- // Method arguments can be passed 'by ref'
- if (corValue.Type == (uint)CorElementType.BYREF) {
- corValue = corValue.CastTo().Dereference();
- }
-
- // Pointers may be used in 'unsafe' code - CorElementType.PTR
- // Classes need to be dereferenced
- while (corValue.Is()) {
- ICorDebugReferenceValue refValue = corValue.CastTo();
- if (refValue.IsNull != 0) {
- return null; // Reference is null
- } else {
- try {
- corValue = refValue.Dereference();
- // TODO: Investigate: Must not acutally be null
- // eg. Assembly.AssemblyHandle See SD2-1117
- if (corValue == null) return null; // Dereference() returned null
- } catch {
- return null; // Error during dereferencing
- }
- }
- }
-
- // Unbox value types
- if (corValue.Is()) {
- corValue = corValue.CastTo().Object.CastTo();
- }
-
- return corValue;
- }
-
- ValueProxy CreateValue()
- {
- ICorDebugValue corValue = this.CorValue;
-
- if (corValue == null) {
- return new NullValue(this);
- }
-
- CorElementType type = ValueProxy.GetCorType(corValue);
-
- switch(type) {
- case CorElementType.BOOLEAN:
- case CorElementType.CHAR:
- case CorElementType.I1:
- case CorElementType.U1:
- case CorElementType.I2:
- case CorElementType.U2:
- case CorElementType.I4:
- case CorElementType.U4:
- case CorElementType.I8:
- case CorElementType.U8:
- case CorElementType.R4:
- case CorElementType.R8:
- case CorElementType.I:
- case CorElementType.U:
- case CorElementType.STRING:
- return new PrimitiveValue(this);
-
- case CorElementType.ARRAY:
- case CorElementType.SZARRAY: // Short-cut for single dimension zero lower bound array
- return new ArrayValue(this);
-
- case CorElementType.VALUETYPE:
- case CorElementType.CLASS:
- case CorElementType.OBJECT: // Short-cut for Class "System.Object"
- return new ObjectValue(this);
-
- default: // Unknown type
- throw new CannotGetValueException("Unknown value type");
- }
- }
-
- public bool SetValue(Value newValue)
- {
- ICorDebugValue corValue = this.RawCorValue;
- ICorDebugValue newCorValue = newValue.RawCorValue;
- if (newCorValue.Type == (uint)CorElementType.BYREF) {
- newCorValue = newCorValue.As().Dereference();
- }
-
- if (corValue.Is()) {
- if (newCorValue.Is()) {
- ICorDebugClass corClass = newCorValue.As().Class;
- ICorDebugValue box = Eval.NewObject(process, corClass).RawCorValue;
- newCorValue = box;
- }
- corValue.CastTo().SetValue(newCorValue.CastTo().Value);
- return true;
- } else {
- return false;
- }
- }
-
- public VariableCollection GetDebugInfo()
- {
- return GetDebugInfo(this.RawCorValue);
- }
-
- public static VariableCollection GetDebugInfo(ICorDebugValue corValue)
- {
- List items = new List();
-
- if (corValue.Is()) {
- List more = new List();
- more.Add(new VariableCollection("type", ((CorElementType)corValue.Type).ToString()));
- more.Add(new VariableCollection("size", corValue.Size.ToString()));
- more.Add(new VariableCollection("address", corValue.Address.ToString("X")));
- items.Add(new VariableCollection("ICorDebugValue", "", more, null));
- }
- if (corValue.Is()) items.Add(new VariableCollection("ICorDebugValue2", "", null, null));
- if (corValue.Is()) {
- List more = new List();
- try {
- byte[] bytes = corValue.CastTo().RawValue;
- for(int i = 0; i < bytes.Length; i += 8) {
- string val = "";
- for(int j = i; j < bytes.Length && j < i + 8; j++) {
- val += bytes[j].ToString("X2") + " ";
- }
- more.Add(new VariableCollection("data" + i.ToString("X2"), val));
- }
- } catch (ArgumentException) {
- more.Add(new VariableCollection("data", "N/A"));
- }
- items.Add(new VariableCollection("ICorDebugGenericValue", "", more, null));
- }
- if (corValue.Is()) {
- List more = new List();
- ICorDebugReferenceValue refValue = corValue.CastTo();
- bool isNull = refValue.IsNull != 0;
- more.Add(new VariableCollection("isNull", isNull.ToString()));
- if (!isNull) {
- more.Add(new VariableCollection("address", refValue.Value.ToString("X")));
- if (refValue.Dereference() != null) {
- VariableCollection deRef = GetDebugInfo(refValue.Dereference());
- more.Add(new VariableCollection("dereferenced", deRef.Value, deRef.SubCollections, deRef.Items));
- } else {
- more.Add(new VariableCollection("dereferenced", "N/A", null, null));
- }
-
- }
- items.Add(new VariableCollection("ICorDebugReferenceValue", "", more, null));
- }
- if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHeapValue", "", null, null));
- if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHeapValue2", "", null, null));
- if (corValue.Is()) {
- List more = new List();
- bool isValue = corValue.CastTo().IsValueClass != 0;
- more.Add(new VariableCollection("isValue", isValue.ToString()));
- items.Add(new VariableCollection("ICorDebugObjectValue", "", more, null));
- }
- if (corValue.Is()) items.Add(new VariableCollection("ICorDebugObjectValue2", "", null, null));
- if (corValue.Is()) {
- List more = new List();
- VariableCollection unboxed = GetDebugInfo(corValue.CastTo().Object.CastTo());
- more.Add(new VariableCollection("unboxed", unboxed.Value, unboxed.SubCollections, unboxed.Items));
- items.Add(new VariableCollection("ICorDebugBoxValue", "", more, null));
- }
- if (corValue.Is()) items.Add(new VariableCollection("ICorDebugStringValue", "", null, null));
- if (corValue.Is()) items.Add(new VariableCollection("ICorDebugArrayValue", "", null, null));
- if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHandleValue", "", null, null));
-
- return new VariableCollection("$debugInfo", ((CorElementType)corValue.Type).ToString(), items.ToArray(), null);
- }
- }
-
- class CannotGetValueException: System.Exception
- {
- public CannotGetValueException(string message):base(message)
- {
-
- }
}
}
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs
deleted file mode 100644
index 0d18c1f3be..0000000000
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-//
-//
-//
-// $Revision$
-//
-
-using System;
-using System.Collections.Generic;
-
-using Debugger.Wrappers.CorDebug;
-
-namespace Debugger
-{
- ///
- ///
- ///
- public class Variable: IExpirable, IMutable
- {
- string name;
- Value val;
- bool hasExpired;
-
- public event EventHandler Expired;
- public event EventHandler Changed;
-
- public Process Process {
- get {
- return val.Process;
- }
- }
-
- public string Name {
- get {
- return name;
- }
- }
-
- public Value Value {
- get {
- return val;
- }
- }
-
- public ValueProxy ValueProxy {
- get {
- return val.ValueProxy;
- }
- }
-
- public bool HasExpired {
- get {
- return hasExpired;
- }
- }
-
- internal Variable(string name, Value @value)
- {
- if (@value == null) throw new ArgumentNullException("value");
-
- this.name = name;
- this.val = @value;
- this.val.Expired += delegate(object sender, EventArgs e) { OnExpired(e); };
- this.val.Changed += delegate(object sender, ProcessEventArgs e) { OnChanged(e); };
-
- if (name.StartsWith("<") && name.Contains(">") && name != "") {
- string middle = name.TrimStart('<').Split('>')[0]; // Get text between '<' and '>'
- if (middle != "") {
- this.name = middle;
- }
- }
- }
-
- protected virtual void OnExpired(EventArgs e)
- {
- if (!hasExpired) {
- hasExpired = true;
- if (Expired != null) {
- Expired(this, e);
- }
- }
- }
-
- protected virtual void OnChanged(ProcessEventArgs e)
- {
- if (Changed != null) {
- Changed(this, e);
- }
- }
- }
-}