Browse Source

Reduce ValueProxy

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2023 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 19 years ago
parent
commit
2cabe3baf6
  1. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs
  2. 4
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
  3. 12
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs
  4. 9
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs
  5. 12
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs
  6. 12
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs
  7. 12
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs
  8. 426
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs
  9. 93
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs
  10. 335
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs
  11. 91
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs

@ -88,7 +88,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -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;

4
src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj

@ -377,18 +377,18 @@ @@ -377,18 +377,18 @@
<Compile Include="Src\Debugger\IExpirable.cs" />
<Compile Include="Src\Variables\Evals\CallFunctionEval.cs" />
<Compile Include="Src\Variables\Evals\NewStringEval.cs" />
<Compile Include="Src\Variables\Variable.cs" />
<Compile Include="Src\Variables\ObjectValue.cs" />
<Compile Include="Src\Debugger\Util.cs" />
<Compile Include="Src\Variables\Evals\NewObjectEval.cs" />
<Compile Include="Src\Debugger\IMutable.cs" />
<Compile Include="Src\Debugger\ExceptionEventArgs.cs" />
<Compile Include="Src\Debugger\Internal\ManagedCallbackSwitch.cs" />
<Compile Include="Src\Variables\Variable2.cs" />
<Compile Include="Src\Variables\ObjectMember.cs" />
<Compile Include="Src\Variables\MethodArgument.cs" />
<Compile Include="Src\Variables\LocalVariable.cs" />
<Compile Include="Src\Variables\ArrayElement.cs" />
<Compile Include="Src\Variables\ValueProxy.cs" />
<Compile Include="Src\Variables\Variable.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="README.TXT" />

12
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs

@ -23,7 +23,7 @@ namespace Debugger @@ -23,7 +23,7 @@ namespace Debugger
protected ICorDebugArrayValue CorArrayValue {
get {
return this.CorValue.CastTo<ICorDebugArrayValue>();
return TheValue.CorValue.CastTo<ICorDebugArrayValue>();
}
}
@ -35,7 +35,7 @@ namespace Debugger @@ -35,7 +35,7 @@ namespace Debugger
public string ElementsType {
get {
return CorTypeToString(corElementType);
return Value.CorTypeToString(corElementType);
}
}
@ -72,7 +72,7 @@ namespace Debugger @@ -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 @@ -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); }
)
);

9
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs

@ -17,12 +17,9 @@ namespace Debugger @@ -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();

12
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs

@ -68,20 +68,20 @@ namespace Debugger @@ -68,20 +68,20 @@ namespace Debugger
internal ObjectValue(Value @value):base(@value)
{
topClass = new ObjectValueClass(this, this.CorValue.As<ICorDebugObjectValue>().Class);
topClass = new ObjectValueClass(this, TheValue.CorValue.As<ICorDebugObjectValue>().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;

12
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs

@ -24,7 +24,7 @@ namespace Debugger @@ -24,7 +24,7 @@ namespace Debugger
ICorDebugObjectValue CorObjectValue {
get {
return objectValue.CorValue.As<ICorDebugObjectValue>();
return objectValue.TheValue.CorValue.As<ICorDebugObjectValue>();
}
}
@ -60,7 +60,7 @@ namespace Debugger @@ -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 @@ -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 @@ -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

12
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs

@ -25,10 +25,10 @@ namespace Debugger @@ -25,10 +25,10 @@ namespace Debugger
public object Primitive {
get {
if (CorType == CorElementType.STRING) {
return (CorValue.CastTo<ICorDebugStringValue>()).String;
if (TheValue.CorType == CorElementType.STRING) {
return (TheValue.CorValue.CastTo<ICorDebugStringValue>()).String;
} else {
return (CorValue.CastTo<ICorDebugGenericValue>()).Value;
return (TheValue.CorValue.CastTo<ICorDebugGenericValue>()).Value;
}
}
set {
@ -40,12 +40,12 @@ namespace Debugger @@ -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<ICorDebugGenericValue>()).Value = newValue;
(TheValue.CorValue.CastTo<ICorDebugGenericValue>()).Value = newValue;
}
this.Value.NotifyChange();
TheValue.NotifyChange();
}
}

426
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs

@ -1,124 +1,407 @@ @@ -1,124 +1,407 @@
// <file>
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using Debugger.Wrappers.CorDebug;
namespace Debugger
{
public abstract class ValueProxy: RemotingObjectBase
/// <summary>
/// Delegate that is used to get value. This delegate may be called at any time and should never return null.
/// </summary>
delegate ICorDebugValue CorValueGetter();
/// <summary>
/// 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)
/// </summary>
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<ProcessEventArgs> 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<ICorDebugHandleValue>())) {
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<ICorDebugHandleValue>()) {
return corValue;
}
corValue = DereferenceUnbox(corValue);
if (corValue != null && corValue.Is<ICorDebugHeapValue2>()) {
return corValue.As<ICorDebugHeapValue2>().CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION).CastTo<ICorDebugValue>();
} 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<ICorDebugReferenceValue>().Dereference();
}
// Pointers may be used in 'unsafe' code - CorElementType.PTR
// Classes need to be dereferenced
while (corValue.Is<ICorDebugReferenceValue>()) {
ICorDebugReferenceValue refValue = corValue.CastTo<ICorDebugReferenceValue>();
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<ICorDebugBoxValue>()) {
corValue = corValue.CastTo<ICorDebugBoxValue>().Object.CastTo<ICorDebugValue>();
}
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<ICorDebugReferenceValue>().Dereference();
}
if (corValue.Is<ICorDebugReferenceValue>()) {
if (newCorValue.Is<ICorDebugObjectValue>()) {
ICorDebugClass corClass = newCorValue.As<ICorDebugObjectValue>().Class;
ICorDebugValue box = Eval.NewObject(process, corClass).RawCorValue;
newCorValue = box;
}
corValue.CastTo<ICorDebugReferenceValue>().SetValue(newCorValue.CastTo<ICorDebugReferenceValue>().Value);
return true;
} else {
return false;
}
}
/// <summary>
/// Returns true if the value is signed or unsigned integer of any size
/// </summary>
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<VariableCollection> items = new List<VariableCollection>();
if (corValue.Is<ICorDebugValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
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<ICorDebugValue2>()) items.Add(new VariableCollection("ICorDebugValue2", "", null, null));
if (corValue.Is<ICorDebugGenericValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
try {
byte[] bytes = corValue.CastTo<ICorDebugGenericValue>().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<ICorDebugReferenceValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
ICorDebugReferenceValue refValue = corValue.CastTo<ICorDebugReferenceValue>();
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<ICorDebugHeapValue>()) items.Add(new VariableCollection("ICorDebugHeapValue", "", null, null));
if (corValue.Is<ICorDebugHeapValue2>()) items.Add(new VariableCollection("ICorDebugHeapValue2", "", null, null));
if (corValue.Is<ICorDebugObjectValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
bool isValue = corValue.CastTo<ICorDebugObjectValue>().IsValueClass != 0;
more.Add(new VariableCollection("isValue", isValue.ToString()));
items.Add(new VariableCollection("ICorDebugObjectValue", "", more, null));
}
if (corValue.Is<ICorDebugObjectValue2>()) items.Add(new VariableCollection("ICorDebugObjectValue2", "", null, null));
if (corValue.Is<ICorDebugBoxValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
VariableCollection unboxed = GetDebugInfo(corValue.CastTo<ICorDebugBoxValue>().Object.CastTo<ICorDebugValue>());
more.Add(new VariableCollection("unboxed", unboxed.Value, unboxed.SubCollections, unboxed.Items));
items.Add(new VariableCollection("ICorDebugBoxValue", "", more, null));
}
if (corValue.Is<ICorDebugStringValue>()) items.Add(new VariableCollection("ICorDebugStringValue", "", null, null));
if (corValue.Is<ICorDebugArrayValue>()) items.Add(new VariableCollection("ICorDebugArrayValue", "", null, null));
if (corValue.Is<ICorDebugHandleValue>()) 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 @@ -145,25 +428,6 @@ namespace Debugger
}
}
/// <summary>
/// Returns true if the value is signed or unsigned integer of any size
/// </summary>
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 @@ -171,4 +435,12 @@ namespace Debugger
return manType.ToString();
}
}
class CannotGetValueException: System.Exception
{
public CannotGetValueException(string message):base(message)
{
}
}
}

93
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using Debugger.Wrappers.CorDebug;
namespace Debugger
{
/// <summary>
/// Provides more specific access
/// </summary>
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;
}
}
}

335
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
// <file>
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
@ -13,358 +13,79 @@ using Debugger.Wrappers.CorDebug; @@ -13,358 +13,79 @@ using Debugger.Wrappers.CorDebug;
namespace Debugger
{
/// <summary>
/// Delegate that is used to get value. This delegate may be called at any time and should never return null.
/// </summary>
delegate ICorDebugValue CorValueGetter();
/// <summary>
/// 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)
/// </summary>
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<ProcessEventArgs> 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<ICorDebugHandleValue>())) {
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<ICorDebugHandleValue>()) {
return corValue;
}
corValue = DereferenceUnbox(corValue);
if (corValue != null && corValue.Is<ICorDebugHeapValue2>()) {
return corValue.As<ICorDebugHeapValue2>().CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION).CastTo<ICorDebugValue>();
} 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 != "<Base class>") {
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<ICorDebugReferenceValue>().Dereference();
}
// Pointers may be used in 'unsafe' code - CorElementType.PTR
// Classes need to be dereferenced
while (corValue.Is<ICorDebugReferenceValue>()) {
ICorDebugReferenceValue refValue = corValue.CastTo<ICorDebugReferenceValue>();
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<ICorDebugBoxValue>()) {
corValue = corValue.CastTo<ICorDebugBoxValue>().Object.CastTo<ICorDebugValue>();
}
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<ICorDebugReferenceValue>().Dereference();
}
if (corValue.Is<ICorDebugReferenceValue>()) {
if (newCorValue.Is<ICorDebugObjectValue>()) {
ICorDebugClass corClass = newCorValue.As<ICorDebugObjectValue>().Class;
ICorDebugValue box = Eval.NewObject(process, corClass).RawCorValue;
newCorValue = box;
}
corValue.CastTo<ICorDebugReferenceValue>().SetValue(newCorValue.CastTo<ICorDebugReferenceValue>().Value);
return true;
} else {
return false;
}
}
public VariableCollection GetDebugInfo()
{
return GetDebugInfo(this.RawCorValue);
}
public static VariableCollection GetDebugInfo(ICorDebugValue corValue)
{
List<VariableCollection> items = new List<VariableCollection>();
if (corValue.Is<ICorDebugValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
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<ICorDebugValue2>()) items.Add(new VariableCollection("ICorDebugValue2", "", null, null));
if (corValue.Is<ICorDebugGenericValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
try {
byte[] bytes = corValue.CastTo<ICorDebugGenericValue>().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<ICorDebugReferenceValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
ICorDebugReferenceValue refValue = corValue.CastTo<ICorDebugReferenceValue>();
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<ICorDebugHeapValue>()) items.Add(new VariableCollection("ICorDebugHeapValue", "", null, null));
if (corValue.Is<ICorDebugHeapValue2>()) items.Add(new VariableCollection("ICorDebugHeapValue2", "", null, null));
if (corValue.Is<ICorDebugObjectValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
bool isValue = corValue.CastTo<ICorDebugObjectValue>().IsValueClass != 0;
more.Add(new VariableCollection("isValue", isValue.ToString()));
items.Add(new VariableCollection("ICorDebugObjectValue", "", more, null));
}
if (corValue.Is<ICorDebugObjectValue2>()) items.Add(new VariableCollection("ICorDebugObjectValue2", "", null, null));
if (corValue.Is<ICorDebugBoxValue>()) {
List<VariableCollection> more = new List<VariableCollection>();
VariableCollection unboxed = GetDebugInfo(corValue.CastTo<ICorDebugBoxValue>().Object.CastTo<ICorDebugValue>());
more.Add(new VariableCollection("unboxed", unboxed.Value, unboxed.SubCollections, unboxed.Items));
items.Add(new VariableCollection("ICorDebugBoxValue", "", more, null));
}
if (corValue.Is<ICorDebugStringValue>()) items.Add(new VariableCollection("ICorDebugStringValue", "", null, null));
if (corValue.Is<ICorDebugArrayValue>()) items.Add(new VariableCollection("ICorDebugArrayValue", "", null, null));
if (corValue.Is<ICorDebugHandleValue>()) 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)
{
}
}
}

91
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs

@ -1,91 +0,0 @@ @@ -1,91 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using Debugger.Wrappers.CorDebug;
namespace Debugger
{
/// <summary>
///
/// </summary>
public class Variable: IExpirable, IMutable
{
string name;
Value val;
bool hasExpired;
public event EventHandler Expired;
public event EventHandler<ProcessEventArgs> 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 != "<Base class>") {
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);
}
}
}
}
Loading…
Cancel
Save