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
image = DebuggerIcons.GetImage(variable); image = DebuggerIcons.GetImage(variable);
this[1].Text = ""; // Icon this[1].Text = ""; // Icon
this[2].Text = variable.Name; 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); this[3].Text = String.Format("0x{0:X}", (variable.ValueProxy as PrimitiveValue).Primitive);
} else { } else {
this[3].Text = variable.ValueProxy.AsString; this[3].Text = variable.ValueProxy.AsString;

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

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

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

@ -23,7 +23,7 @@ namespace Debugger
protected ICorDebugArrayValue CorArrayValue { protected ICorDebugArrayValue CorArrayValue {
get { get {
return this.CorValue.CastTo<ICorDebugArrayValue>(); return TheValue.CorValue.CastTo<ICorDebugArrayValue>();
} }
} }
@ -35,7 +35,7 @@ namespace Debugger
public string ElementsType { public string ElementsType {
get { get {
return CorTypeToString(corElementType); return Value.CorTypeToString(corElementType);
} }
} }
@ -72,7 +72,7 @@ namespace Debugger
bool IsCorValueCompatible { bool IsCorValueCompatible {
get { get {
ArrayValue freshValue = this.FreshValue as ArrayValue; ArrayValue freshValue = TheValue.ValueProxy as ArrayValue;
return freshValue != null && return freshValue != null &&
freshValue.ElementsType == this.ElementsType && freshValue.ElementsType == this.ElementsType &&
freshValue.Lenght == this.Lenght && freshValue.Lenght == this.Lenght &&
@ -119,9 +119,9 @@ namespace Debugger
elementName, elementName,
indices, indices,
new Value( new Value(
Process, TheValue.Process,
new IExpirable[] {this.Value}, new IExpirable[] {this.TheValue},
new IMutable[] {this.Value}, new IMutable[] {this.TheValue},
delegate { return GetCorValueOfItem(indices); } delegate { return GetCorValueOfItem(indices); }
) )
); );

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

@ -17,12 +17,9 @@ namespace Debugger
} }
} }
public override string Type public override string Type {
{ get {
get switch (TheValue.CorType) {
{
switch (CorType)
{
case CorElementType.SZARRAY: case CorElementType.SZARRAY:
case CorElementType.ARRAY: return typeof(System.Array).ToString(); case CorElementType.ARRAY: return typeof(System.Array).ToString();
case CorElementType.OBJECT: return typeof(System.Object).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
internal ObjectValue(Value @value):base(@value) 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; Module module = GetClass("System.Object").Module;
ICorDebugFunction corFunction = module.GetMethod("System.Object", "ToString", 0); ICorDebugFunction corFunction = module.GetMethod("System.Object", "ToString", 0);
toStringText = new CallFunctionEval(this.Process, toStringText = new CallFunctionEval(TheValue.Process,
new IExpirable[] {this.Value}, new IExpirable[] {this.TheValue},
new IMutable[] {this.Value}, new IMutable[] {this.TheValue},
corFunction, corFunction,
this.Value, TheValue,
new Value[] {}); new Value[] {});
} }
internal bool IsCorValueCompatible { internal bool IsCorValueCompatible {
get { get {
ObjectValue freshValue = this.FreshValue as ObjectValue; ObjectValue freshValue = TheValue.ValueProxy as ObjectValue;
return freshValue != null && return freshValue != null &&
topClass.Module == freshValue.TopClass.Module && topClass.Module == freshValue.TopClass.Module &&
topClass.ClassToken == freshValue.TopClass.ClassToken; topClass.ClassToken == freshValue.TopClass.ClassToken;

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

@ -24,7 +24,7 @@ namespace Debugger
ICorDebugObjectValue CorObjectValue { ICorDebugObjectValue CorObjectValue {
get { get {
return objectValue.CorValue.As<ICorDebugObjectValue>(); return objectValue.TheValue.CorValue.As<ICorDebugObjectValue>();
} }
} }
@ -60,7 +60,7 @@ namespace Debugger
public ObjectValueClass(ObjectValue objectValue, ICorDebugClass corClass) public ObjectValueClass(ObjectValue objectValue, ICorDebugClass corClass)
{ {
this.process = objectValue.Process; this.process = objectValue.TheValue.Process;
this.objectValue = objectValue; this.objectValue = objectValue;
this.module = process.GetModule(corClass.Module); this.module = process.GetModule(corClass.Module);
this.corClass = corClass; this.corClass = corClass;
@ -139,8 +139,8 @@ namespace Debugger
(field.IsPublic ? ObjectMember.Flags.Public : ObjectMember.Flags.None), (field.IsPublic ? ObjectMember.Flags.Public : ObjectMember.Flags.None),
new Value( new Value(
process, process,
new IExpirable[] {this.objectValue.Value}, new IExpirable[] {this.objectValue.TheValue},
new IMutable[] {this.objectValue.Value}, new IMutable[] {this.objectValue.TheValue},
delegate { return GetCorValueOfField(field); } delegate { return GetCorValueOfField(field); }
) )
); );
@ -186,10 +186,10 @@ namespace Debugger
flags, flags,
new CallFunctionEval( new CallFunctionEval(
process, process,
new IExpirable[] {this.objectValue.Value}, new IExpirable[] {this.objectValue.TheValue},
new IMutable[] {process.DebugeeState}, new IMutable[] {process.DebugeeState},
Module.CorModule.GetFunctionFromToken(method.Token), Module.CorModule.GetFunctionFromToken(method.Token),
method.IsStatic ? null : this.objectValue.Value, // this method.IsStatic ? null : this.objectValue.TheValue, // this
new Value[] {} new Value[] {}
) )
); // args ); // args

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

@ -25,10 +25,10 @@ namespace Debugger
public object Primitive { public object Primitive {
get { get {
if (CorType == CorElementType.STRING) { if (TheValue.CorType == CorElementType.STRING) {
return (CorValue.CastTo<ICorDebugStringValue>()).String; return (TheValue.CorValue.CastTo<ICorDebugStringValue>()).String;
} else { } else {
return (CorValue.CastTo<ICorDebugGenericValue>()).Value; return (TheValue.CorValue.CastTo<ICorDebugGenericValue>()).Value;
} }
} }
set { set {
@ -40,12 +40,12 @@ namespace Debugger
throw new NotSupportedException("Can not convert " + value.GetType().ToString() + " to " + ManagedType.ToString()); throw new NotSupportedException("Can not convert " + value.GetType().ToString() + " to " + ManagedType.ToString());
} }
if (CorType == CorElementType.STRING) { if (TheValue.CorType == CorElementType.STRING) {
throw new NotSupportedException(); throw new NotSupportedException();
} else { } 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 @@
// <file> // <file>
// <copyright see="prj:///doc/copyright.txt"/> // <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.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> // <version>$Revision$</version>
// </file> // </file>
using System; using System;
using System.Collections.Generic;
using Debugger.Wrappers.CorDebug; using Debugger.Wrappers.CorDebug;
namespace Debugger 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 { public Process Process {
get { get {
return val.Process; return process;
} }
} }
public Value Value { public ICorDebugValue CorValue {
get { get {
return val; return DereferenceUnbox(RawCorValue);
} }
} }
internal ICorDebugValue CorValue { internal CorElementType CorType {
get { get {
return val.CorValue; return GetCorType(this.CorValue);
} }
} }
protected ValueProxy FreshValue { internal static CorElementType GetCorType(ICorDebugValue corValue)
get { {
return val.ValueProxy; if (corValue == null) {
return (CorElementType)0;
} }
return (CorElementType)corValue.Type;
} }
internal CorElementType CorType { protected virtual ICorDebugValue RawCorValue {
get { 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 { public ValueProxy ValueProxy {
get; get {
} if (currentValue == null) {
try {
public virtual string Type { currentValue = CreateValue();
get{ } catch (CannotGetValueException e) {
return CorTypeToString(CorType); currentValue = new UnavailableValue(this, e.Message);
} }
}
return currentValue;
}
} }
public virtual Type ManagedType { public bool HasExpired {
get { get {
return CorTypeToManagedType(CorType); return isExpired;
} }
} }
public bool MayHaveSubVariables { public ICorDebugValue SoftReference {
get { get {
#if DEBUG if (this.HasExpired) throw new DebuggerException("CorValue has expired");
return true;
#else ICorDebugValue corValue = RawCorValue;
return GetMayHaveSubVariables(); if (corValue != null && corValue.Is<ICorDebugHandleValue>()) {
#endif 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 { void AddExpireDependency(IExpirable dependency)
get { {
VariableCollection subVars = GetSubVariables(); if (dependency.HasExpired) {
#if DEBUG MakeExpired();
return new VariableCollection(subVars.Name, } else {
subVars.Value, dependency.Expired += delegate { MakeExpired(); };
Util.MergeLists(val.GetDebugInfo(), subVars.SubCollections).ToArray(),
subVars.Items);
#else
return subVars;
#endif
} }
} }
protected virtual VariableCollection GetSubVariables() void AddMutateDependency(IMutable dependency)
{ {
return new VariableCollection(new Variable[] {}); dependency.Changed += DependencyChanged;
} }
public Variable this[string variableName] { void MakeExpired()
get { {
foreach(Variable v in SubVariables) { if (!isExpired) {
if (v.Name == variableName) return v; 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"); NotifyChange();
this.val = @value;
} }
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) { 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) internal static System.Type CorTypeToManagedType(CorElementType corType)
{ {
switch(corType) switch(corType)
@ -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) internal static string CorTypeToString(CorElementType corType)
{ {
Type manType = CorTypeToManagedType(corType); Type manType = CorTypeToManagedType(corType);
@ -171,4 +435,12 @@ namespace Debugger
return manType.ToString(); 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 @@
// <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 @@
// <file> // <file>
// <copyright see="prj:///doc/copyright.txt"/> // <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.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> // <version>$Revision$</version>
// </file> // </file>
@ -13,358 +13,79 @@ using Debugger.Wrappers.CorDebug;
namespace Debugger namespace Debugger
{ {
/// <summary> /// <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> /// </summary>
public class Value: IExpirable, IMutable public class Variable: IExpirable, IMutable
{ {
protected Process process; string name;
Value val;
CorValueGetter corValueGetter; bool hasExpired;
IMutable[] mutateDependencies;
protected ValueProxy currentValue;
protected ICorDebugValue currentCorValue;
protected PauseSession currentCorValuePauseSession;
bool isExpired = false;
public event EventHandler Expired; public event EventHandler Expired;
public event EventHandler<ProcessEventArgs> Changed; public event EventHandler<ProcessEventArgs> Changed;
public Process Process { public Process Process {
get { get {
return process; return val.Process;
} }
} }
public ICorDebugValue CorValue { public string Name {
get { get {
return DereferenceUnbox(RawCorValue); return name;
} }
} }
protected virtual ICorDebugValue RawCorValue { public Value Value {
get { get {
if (this.HasExpired) throw new CannotGetValueException("CorValue has expired"); return val;
if (currentCorValue == null || (currentCorValuePauseSession != process.PauseSession && !currentCorValue.Is<ICorDebugHandleValue>())) {
currentCorValue = corValueGetter();
currentCorValuePauseSession = process.PauseSession;
}
return currentCorValue;
} }
} }
public ValueProxy ValueProxy { public ValueProxy ValueProxy {
get { get {
if (currentValue == null) { return val.ValueProxy;
try {
currentValue = CreateValue();
} catch (CannotGetValueException e) {
currentValue = new UnavailableValue(this, e.Message);
}
}
return currentValue;
} }
} }
public bool HasExpired { public bool HasExpired {
get { get {
return isExpired; return hasExpired;
}
}
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
}
} }
} }
internal Value(Process process, internal Variable(string name, Value @value)
IExpirable[] expireDependencies,
IMutable[] mutateDependencies,
CorValueGetter corValueGetter)
{ {
this.process = process; if (@value == null) throw new ArgumentNullException("value");
foreach(IExpirable exp in expireDependencies) { this.name = name;
AddExpireDependency(exp); this.val = @value;
} this.val.Expired += delegate(object sender, EventArgs e) { OnExpired(e); };
AddExpireDependency(process); this.val.Changed += delegate(object sender, ProcessEventArgs e) { OnChanged(e); };
this.mutateDependencies = mutateDependencies; if (name.StartsWith("<") && name.Contains(">") && name != "<Base class>") {
if (!this.HasExpired) { string middle = name.TrimStart('<').Split('>')[0]; // Get text between '<' and '>'
foreach(IMutable mut in mutateDependencies) { if (middle != "") {
AddMutateDependency(mut); this.name = middle;
} }
} }
this.corValueGetter = corValueGetter;
} }
void AddExpireDependency(IExpirable dependency) protected virtual void OnExpired(EventArgs e)
{
if (dependency.HasExpired) {
MakeExpired();
} else {
dependency.Expired += delegate { MakeExpired(); };
}
}
void AddMutateDependency(IMutable dependency)
{
dependency.Changed += DependencyChanged;
}
void MakeExpired()
{ {
if (!isExpired) { if (!hasExpired) {
isExpired = true; hasExpired = true;
OnExpired(new ValueEventArgs(this)); if (Expired != null) {
foreach(IMutable mut in mutateDependencies) { Expired(this, e);
mut.Changed -= DependencyChanged;
} }
} }
} }
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) protected virtual void OnChanged(ProcessEventArgs e)
{ {
if (Changed != null) { if (Changed != null) {
Changed(this, e); 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 @@
// <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