Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2185 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
79 changed files with 2629 additions and 2275 deletions
@ -0,0 +1,23 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 1965 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Text; |
||||||
|
using System.Threading; |
||||||
|
|
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// <para> This library provides features for debugging managed applications. </para>
|
||||||
|
/// </summary>
|
||||||
|
class NamespaceDoc |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -1,29 +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 |
|
||||||
{ |
|
||||||
public class ArrayElement: Variable |
|
||||||
{ |
|
||||||
uint[] indicies; |
|
||||||
|
|
||||||
public uint[] Indicies { |
|
||||||
get { return indicies; } |
|
||||||
} |
|
||||||
|
|
||||||
public ArrayElement(string name, uint[] indicies, Value @value) |
|
||||||
:base (name, @value) |
|
||||||
{ |
|
||||||
this.indicies = indicies; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,166 +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; |
|
||||||
|
|
||||||
//TODO: Support for lower bound
|
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
public class ArrayValue: ValueProxy |
|
||||||
{ |
|
||||||
uint[] dimensions; |
|
||||||
|
|
||||||
uint lenght; |
|
||||||
CorElementType corElementType; |
|
||||||
readonly uint rank; |
|
||||||
|
|
||||||
protected ICorDebugArrayValue CorArrayValue { |
|
||||||
get { |
|
||||||
return TheValue.CorValue.CastTo<ICorDebugArrayValue>(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public uint Lenght { |
|
||||||
get { |
|
||||||
return lenght; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public string ElementsType { |
|
||||||
get { |
|
||||||
return Value.CorTypeToString(corElementType); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public uint Rank { |
|
||||||
get { |
|
||||||
return rank; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override string AsString { |
|
||||||
get { |
|
||||||
string txt = "{" + ElementsType + "["; |
|
||||||
for (int i = 0; i < rank; i++) { |
|
||||||
txt += dimensions[i].ToString() + ","; |
|
||||||
} |
|
||||||
txt = txt.TrimEnd(new char[] {','}) + "]}"; |
|
||||||
return txt; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
internal unsafe ArrayValue(Value @value):base(@value) |
|
||||||
{ |
|
||||||
corElementType = (CorElementType)CorArrayValue.ElementType; |
|
||||||
|
|
||||||
rank = CorArrayValue.Rank; |
|
||||||
lenght = CorArrayValue.Count; |
|
||||||
|
|
||||||
dimensions = new uint[rank]; |
|
||||||
fixed (void* pDimensions = dimensions) { |
|
||||||
CorArrayValue.GetDimensions(rank, new IntPtr(pDimensions)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool IsCorValueCompatible { |
|
||||||
get { |
|
||||||
ArrayValue freshValue = TheValue.ValueProxy as ArrayValue; |
|
||||||
return freshValue != null && |
|
||||||
freshValue.ElementsType == this.ElementsType && |
|
||||||
freshValue.Lenght == this.Lenght && |
|
||||||
freshValue.Rank == this.Rank; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Variable this[uint index] { |
|
||||||
get { |
|
||||||
return this[new uint[] {index}]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Variable this[uint index1, uint index2] { |
|
||||||
get { |
|
||||||
return this[new uint[] {index1, index2}]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Variable this[uint index1, uint index2, uint index3] { |
|
||||||
get { |
|
||||||
return this[new uint[] {index1, index2, index3}]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Variable this[uint[] indices] { |
|
||||||
get { |
|
||||||
return GetItem(indices); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Variable GetItem(uint[] itemIndices) |
|
||||||
{ |
|
||||||
uint[] indices = (uint[])itemIndices.Clone(); |
|
||||||
|
|
||||||
if (indices.Length != rank) throw new DebuggerException("Given indicies does not match array size."); |
|
||||||
|
|
||||||
string elementName = "["; |
|
||||||
for (int i = 0; i < indices.Length; i++) |
|
||||||
elementName += indices[i].ToString() + ","; |
|
||||||
elementName = elementName.TrimEnd(new char[] {','}) + "]"; |
|
||||||
|
|
||||||
return new ArrayElement( |
|
||||||
elementName, |
|
||||||
indices, |
|
||||||
new Value( |
|
||||||
TheValue.Process, |
|
||||||
new IExpirable[] {this.TheValue}, |
|
||||||
new IMutable[] {this.TheValue}, |
|
||||||
delegate { return GetCorValueOfItem(indices); } |
|
||||||
) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
unsafe ICorDebugValue GetCorValueOfItem(uint[] indices) |
|
||||||
{ |
|
||||||
if (!IsCorValueCompatible) throw new CannotGetValueException("Value is not the same array"); |
|
||||||
fixed (void* pIndices = indices) { |
|
||||||
return CorArrayValue.GetElement(rank, new IntPtr(pIndices)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected override bool GetMayHaveSubVariables() |
|
||||||
{ |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
protected override VariableCollection GetSubVariables() |
|
||||||
{ |
|
||||||
return new VariableCollection(GetSubVariablesEnum()); |
|
||||||
} |
|
||||||
|
|
||||||
IEnumerable<Variable> GetSubVariablesEnum() |
|
||||||
{ |
|
||||||
uint[] indices = new uint[rank]; |
|
||||||
|
|
||||||
while(true) { // Go thought all combinations
|
|
||||||
for (uint i = rank - 1; i >= 1; i--) |
|
||||||
if (indices[i] >= dimensions[i]) { |
|
||||||
indices[i] = 0; |
|
||||||
indices[i-1]++; |
|
||||||
} |
|
||||||
if (indices[0] >= dimensions[0]) break; // We are done
|
|
||||||
|
|
||||||
yield return GetItem(indices); |
|
||||||
|
|
||||||
indices[rank - 1]++; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,57 +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 |
|
||||||
{ |
|
||||||
class CallFunctionEval: Eval |
|
||||||
{ |
|
||||||
ICorDebugFunction corFunction; |
|
||||||
Value thisValue; |
|
||||||
Value[] args; |
|
||||||
|
|
||||||
public CallFunctionEval(Process process, |
|
||||||
IExpirable[] expireDependencies, |
|
||||||
IMutable[] mutateDependencies, |
|
||||||
ICorDebugFunction corFunction, |
|
||||||
Value thisValue, |
|
||||||
Value[] args) |
|
||||||
:base(process, expireDependencies, mutateDependencies) |
|
||||||
{ |
|
||||||
this.corFunction = corFunction; |
|
||||||
this.thisValue = thisValue; |
|
||||||
this.args = args; |
|
||||||
} |
|
||||||
|
|
||||||
protected override void StartEvaluation() |
|
||||||
{ |
|
||||||
List<ICorDebugValue> corArgs = new List<ICorDebugValue>(); |
|
||||||
try { |
|
||||||
if (thisValue != null) { |
|
||||||
ValueProxy val = thisValue.ValueProxy; |
|
||||||
if (!(val is ObjectValue)) { |
|
||||||
throw new EvalSetupException("Can not evaluate on a value which is not an object"); |
|
||||||
} |
|
||||||
if (!((ObjectValue)val).IsInClassHierarchy(corFunction.Class)) { |
|
||||||
throw new EvalSetupException("Can not evaluate because the object does not contain specified function"); |
|
||||||
} |
|
||||||
corArgs.Add(thisValue.SoftReference); |
|
||||||
} |
|
||||||
foreach(Value arg in args) { |
|
||||||
corArgs.Add(arg.SoftReference); |
|
||||||
} |
|
||||||
} catch (CannotGetValueException e) { |
|
||||||
throw new EvalSetupException(e.Message); |
|
||||||
} |
|
||||||
|
|
||||||
corEval.CallFunction(corFunction, (uint)corArgs.Count, corArgs.ToArray()); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,31 +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 Debugger.Wrappers.CorDebug; |
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
class NewObjectEval: Eval |
|
||||||
{ |
|
||||||
ICorDebugClass classToCreate; |
|
||||||
|
|
||||||
public NewObjectEval(Process process, |
|
||||||
IExpirable[] expireDependencies, |
|
||||||
IMutable[] mutateDependencies, |
|
||||||
ICorDebugClass classToCreate) |
|
||||||
:base(process, expireDependencies, mutateDependencies) |
|
||||||
{ |
|
||||||
this.classToCreate = classToCreate; |
|
||||||
} |
|
||||||
|
|
||||||
protected override void StartEvaluation() |
|
||||||
{ |
|
||||||
corEval.NewObjectNoConstructor(classToCreate); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,30 +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; |
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
class NewStringEval: Eval |
|
||||||
{ |
|
||||||
string textToCreate; |
|
||||||
|
|
||||||
public NewStringEval(Process process, |
|
||||||
IExpirable[] expireDependencies, |
|
||||||
IMutable[] mutateDependencies, |
|
||||||
string textToCreate) |
|
||||||
:base(process, expireDependencies, mutateDependencies) |
|
||||||
{ |
|
||||||
this.textToCreate = textToCreate; |
|
||||||
} |
|
||||||
|
|
||||||
protected override void StartEvaluation() |
|
||||||
{ |
|
||||||
corEval.NewString(textToCreate); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,31 +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 |
|
||||||
{ |
|
||||||
public class MethodArgument: Variable |
|
||||||
{ |
|
||||||
int index; |
|
||||||
|
|
||||||
public int Index { |
|
||||||
get { |
|
||||||
return index; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public MethodArgument(string name, int index, Value @value) |
|
||||||
:base (name, @value) |
|
||||||
{ |
|
||||||
this.index = index; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,43 +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; |
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
public class NullValue: ValueProxy |
|
||||||
{ |
|
||||||
public override string AsString { |
|
||||||
get { |
|
||||||
return "<null reference>"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
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(); |
|
||||||
case CorElementType.STRING: return typeof(System.String).ToString(); |
|
||||||
case CorElementType.CLASS: return "<class>"; |
|
||||||
default: return string.Empty; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal unsafe NullValue(Value @value):base(@value) |
|
||||||
{ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
protected override bool GetMayHaveSubVariables() |
|
||||||
{ |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,50 +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>
|
|
||||||
/// Provides information about a member of a given object.
|
|
||||||
/// In particular, it allows to access the value.
|
|
||||||
/// </summary>
|
|
||||||
public class ObjectMember: Variable |
|
||||||
{ |
|
||||||
[Flags] |
|
||||||
public enum Flags { Default = Public, None = 0, Public = 1, Static = 2, PublicStatic = Public | Static}; |
|
||||||
|
|
||||||
Flags memberFlags; |
|
||||||
|
|
||||||
public Flags MemberFlags { |
|
||||||
get { |
|
||||||
return memberFlags; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsStatic { |
|
||||||
get { |
|
||||||
return (memberFlags & Flags.Static) != 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsPublic { |
|
||||||
get { |
|
||||||
return (memberFlags & Flags.Public) != 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ObjectMember(string name, Flags flags, Value @value) |
|
||||||
:base (name, @value) |
|
||||||
{ |
|
||||||
this.memberFlags = flags; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,101 +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 |
|
||||||
{ |
|
||||||
public class ObjectValue: ValueProxy |
|
||||||
{ |
|
||||||
ObjectValueClass topClass; |
|
||||||
Value toStringText; |
|
||||||
|
|
||||||
public override string AsString { |
|
||||||
get { |
|
||||||
return "{" + Type + "}"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Value ToStringText { |
|
||||||
get { |
|
||||||
return toStringText; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override string Type { |
|
||||||
get { |
|
||||||
return topClass.Type; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ObjectValueClass TopClass { |
|
||||||
get { |
|
||||||
return topClass; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public IEnumerable<ObjectValueClass> Classes { |
|
||||||
get { |
|
||||||
ObjectValueClass currentClass = topClass; |
|
||||||
do { |
|
||||||
yield return currentClass; |
|
||||||
currentClass = currentClass.BaseClass; |
|
||||||
} while (currentClass != null); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ObjectValueClass GetClass(string type) |
|
||||||
{ |
|
||||||
foreach(ObjectValueClass cls in Classes) { |
|
||||||
if (cls.Type == type) return cls; |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
internal bool IsInClassHierarchy(ICorDebugClass corClass) |
|
||||||
{ |
|
||||||
foreach(ObjectValueClass cls in Classes) { |
|
||||||
if (cls.CorClass == corClass) return true; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
internal ObjectValue(Value @value):base(@value) |
|
||||||
{ |
|
||||||
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(TheValue.Process, |
|
||||||
new IExpirable[] {this.TheValue}, |
|
||||||
new IMutable[] {this.TheValue}, |
|
||||||
corFunction, |
|
||||||
TheValue, |
|
||||||
new Value[] {}); |
|
||||||
} |
|
||||||
|
|
||||||
internal bool IsCorValueCompatible { |
|
||||||
get { |
|
||||||
ObjectValue freshValue = TheValue.ValueProxy as ObjectValue; |
|
||||||
return freshValue != null && |
|
||||||
topClass.Module == freshValue.TopClass.Module && |
|
||||||
topClass.ClassToken == freshValue.TopClass.ClassToken; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected override bool GetMayHaveSubVariables() |
|
||||||
{ |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
protected override VariableCollection GetSubVariables() |
|
||||||
{ |
|
||||||
return topClass.SubVariables; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,232 +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; |
|
||||||
using Debugger.Wrappers.MetaData; |
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
public class ObjectValueClass: RemotingObjectBase |
|
||||||
{ |
|
||||||
Process process; |
|
||||||
|
|
||||||
ObjectValue objectValue; |
|
||||||
|
|
||||||
Module module; |
|
||||||
ICorDebugClass corClass; |
|
||||||
TypeDefProps classProps; |
|
||||||
|
|
||||||
ICorDebugObjectValue CorObjectValue { |
|
||||||
get { |
|
||||||
return objectValue.TheValue.CorValue.As<ICorDebugObjectValue>(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool IsCorValueCompatible { |
|
||||||
get { |
|
||||||
return objectValue.IsCorValueCompatible; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public Module Module { |
|
||||||
get { |
|
||||||
return module; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public string Type { |
|
||||||
get{ |
|
||||||
return classProps.Name; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal ICorDebugClass CorClass { |
|
||||||
get { |
|
||||||
return corClass; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public uint ClassToken { |
|
||||||
get { |
|
||||||
return classProps.Token; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ObjectValueClass(ObjectValue objectValue, ICorDebugClass corClass) |
|
||||||
{ |
|
||||||
this.process = objectValue.TheValue.Process; |
|
||||||
this.objectValue = objectValue; |
|
||||||
this.module = process.GetModule(corClass.Module); |
|
||||||
this.corClass = corClass; |
|
||||||
this.classProps = Module.MetaData.GetTypeDefProps(corClass.Token); |
|
||||||
} |
|
||||||
|
|
||||||
public VariableCollection SubVariables { |
|
||||||
get { |
|
||||||
return new VariableCollection("Base class", |
|
||||||
"{" + Type + "}", |
|
||||||
SubCollections, |
|
||||||
GetSubVariables(ObjectMember.Flags.Public, ObjectMember.Flags.PublicStatic)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
IEnumerable<VariableCollection> SubCollections { |
|
||||||
get { |
|
||||||
ObjectValueClass baseClass = BaseClass; |
|
||||||
VariableCollection privateStatic = new VariableCollection("Private static members", |
|
||||||
String.Empty, |
|
||||||
new VariableCollection[0], |
|
||||||
GetSubVariables(ObjectMember.Flags.Static, ObjectMember.Flags.PublicStatic)); |
|
||||||
VariableCollection privateInstance = new VariableCollection("Private members", |
|
||||||
String.Empty, |
|
||||||
privateStatic.IsEmpty? new VariableCollection[0] : new VariableCollection[] {privateStatic}, |
|
||||||
GetSubVariables(ObjectMember.Flags.None, ObjectMember.Flags.PublicStatic)); |
|
||||||
VariableCollection publicStatic = new VariableCollection("Static members", |
|
||||||
String.Empty, |
|
||||||
new VariableCollection[0], |
|
||||||
GetSubVariables(ObjectMember.Flags.PublicStatic, ObjectMember.Flags.PublicStatic)); |
|
||||||
if (baseClass != null) { |
|
||||||
yield return baseClass.SubVariables; |
|
||||||
} |
|
||||||
if (!privateInstance.IsEmpty) { |
|
||||||
yield return privateInstance; |
|
||||||
} |
|
||||||
if (!publicStatic.IsEmpty) { |
|
||||||
yield return publicStatic; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
IEnumerable<Variable> GetSubVariables(ObjectMember.Flags requiredFlags, ObjectMember.Flags mask) { |
|
||||||
foreach(ObjectMember var in GetFieldVariables()) { |
|
||||||
if ((var.MemberFlags & mask) == requiredFlags) { |
|
||||||
yield return var; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
foreach(ObjectMember var in GetPropertyVariables()) { |
|
||||||
if ((var.MemberFlags & mask) == requiredFlags) { |
|
||||||
yield return var; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ObjectValueClass BaseClass { |
|
||||||
get { |
|
||||||
ICorDebugClass superClass = GetSuperClass(process, corClass); |
|
||||||
if (superClass != null) { |
|
||||||
return new ObjectValueClass(objectValue, superClass); |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public IEnumerable<ObjectMember> GetFieldVariables() |
|
||||||
{ |
|
||||||
foreach(FieldProps f in Module.MetaData.EnumFields(ClassToken)) { |
|
||||||
FieldProps field = f; // One per scope/delegate
|
|
||||||
if (field.IsStatic && field.IsLiteral) continue; // Skip field
|
|
||||||
yield return new ObjectMember( |
|
||||||
field.Name, |
|
||||||
(field.IsStatic ? ObjectMember.Flags.Static : ObjectMember.Flags.None) | |
|
||||||
(field.IsPublic ? ObjectMember.Flags.Public : ObjectMember.Flags.None), |
|
||||||
new Value( |
|
||||||
process, |
|
||||||
new IExpirable[] {this.objectValue.TheValue}, |
|
||||||
new IMutable[] {this.objectValue.TheValue}, |
|
||||||
delegate { return GetCorValueOfField(field); } |
|
||||||
) |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ICorDebugValue GetCorValueOfField(FieldProps field) |
|
||||||
{ |
|
||||||
if (!IsCorValueCompatible) throw new CannotGetValueException("Object type changed"); |
|
||||||
|
|
||||||
// Current frame is used to resolve context specific static values (eg. ThreadStatic)
|
|
||||||
ICorDebugFrame curFrame = null; |
|
||||||
if (process.IsPaused && process.SelectedThread != null && process.SelectedThread.LastFunction != null && process.SelectedThread.LastFunction.CorILFrame != null) { |
|
||||||
curFrame = process.SelectedThread.LastFunction.CorILFrame.CastTo<ICorDebugFrame>(); |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
if (field.IsStatic) { |
|
||||||
return corClass.GetStaticFieldValue(field.Token, curFrame); |
|
||||||
} else { |
|
||||||
return CorObjectValue.GetFieldValue(corClass, field.Token); |
|
||||||
} |
|
||||||
} catch { |
|
||||||
throw new CannotGetValueException("Can not get value of field"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
IEnumerable<MethodProps> Methods { |
|
||||||
get { |
|
||||||
return this.Module.MetaData.EnumMethods(this.ClassToken); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public IEnumerable<ObjectMember> GetPropertyVariables() |
|
||||||
{ |
|
||||||
foreach(MethodProps m in Methods) { |
|
||||||
MethodProps method = m; // One per scope/delegate
|
|
||||||
if (method.HasSpecialName && method.Name.StartsWith("get_") && method.Name != "get_Item") { |
|
||||||
ObjectMember.Flags flags = (method.IsStatic ? ObjectMember.Flags.Static : ObjectMember.Flags.None) | |
|
||||||
(method.IsPublic ? ObjectMember.Flags.Public : ObjectMember.Flags.None); |
|
||||||
yield return new ObjectMember( |
|
||||||
method.Name.Remove(0, 4), |
|
||||||
flags, |
|
||||||
new CallFunctionEval( |
|
||||||
process, |
|
||||||
new IExpirable[] {this.objectValue.TheValue}, |
|
||||||
new IMutable[] {process.DebugeeState}, |
|
||||||
Module.CorModule.GetFunctionFromToken(method.Token), |
|
||||||
method.IsStatic ? null : this.objectValue.TheValue, // this
|
|
||||||
new Value[] {} |
|
||||||
) |
|
||||||
); // args
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected static ICorDebugClass GetSuperClass(Process process, ICorDebugClass currClass) |
|
||||||
{ |
|
||||||
Module currModule = process.GetModule(currClass.Module); |
|
||||||
uint superToken = currModule.MetaData.GetTypeDefProps(currClass.Token).SuperClassToken; |
|
||||||
|
|
||||||
// It has no base class
|
|
||||||
if ((superToken & 0x00FFFFFF) == 0x00000000) return null; |
|
||||||
|
|
||||||
// TypeDef - Localy defined
|
|
||||||
if ((superToken & 0xFF000000) == 0x02000000) { |
|
||||||
return currModule.CorModule.GetClassFromToken(superToken); |
|
||||||
} |
|
||||||
|
|
||||||
// TypeRef - Referencing to external assembly
|
|
||||||
if ((superToken & 0xFF000000) == 0x01000000) { |
|
||||||
string fullTypeName = currModule.MetaData.GetTypeRefProps(superToken).Name; |
|
||||||
|
|
||||||
foreach (Module superModule in process.Modules) { |
|
||||||
// TODO: Does not work for nested
|
|
||||||
// TODO: preservesig
|
|
||||||
try { |
|
||||||
uint token = superModule.MetaData.FindTypeDefByName(fullTypeName, 0).Token; |
|
||||||
return superModule.CorModule.GetClassFromToken(token); |
|
||||||
} catch { |
|
||||||
continue; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
throw new DebuggerException("Superclass not found"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,61 +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.ComponentModel; |
|
||||||
using Debugger.Wrappers.CorDebug; |
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
public class PrimitiveValue: ValueProxy |
|
||||||
{ |
|
||||||
public override string AsString { |
|
||||||
get { |
|
||||||
if (Primitive != null) { |
|
||||||
return Primitive.ToString(); |
|
||||||
} else { |
|
||||||
return String.Empty; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public object Primitive { |
|
||||||
get { |
|
||||||
if (TheValue.CorType == CorElementType.STRING) { |
|
||||||
return (TheValue.CorValue.CastTo<ICorDebugStringValue>()).String; |
|
||||||
} else { |
|
||||||
return (TheValue.CorValue.CastTo<ICorDebugGenericValue>()).Value; |
|
||||||
} |
|
||||||
} |
|
||||||
set { |
|
||||||
object newValue; |
|
||||||
TypeConverter converter = TypeDescriptor.GetConverter(ManagedType); |
|
||||||
try { |
|
||||||
newValue = converter.ConvertFrom(value); |
|
||||||
} catch { |
|
||||||
throw new NotSupportedException("Can not convert " + value.GetType().ToString() + " to " + ManagedType.ToString()); |
|
||||||
} |
|
||||||
|
|
||||||
if (TheValue.CorType == CorElementType.STRING) { |
|
||||||
throw new NotSupportedException(); |
|
||||||
} else { |
|
||||||
(TheValue.CorValue.CastTo<ICorDebugGenericValue>()).Value = newValue; |
|
||||||
} |
|
||||||
TheValue.NotifyChange(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal PrimitiveValue(Value @value):base(@value) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
protected override bool GetMayHaveSubVariables() |
|
||||||
{ |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,296 +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.Runtime.InteropServices; |
|
||||||
|
|
||||||
namespace Debugger { |
|
||||||
|
|
||||||
unsafe class SignatureStream { |
|
||||||
byte[] signature; |
|
||||||
int currentPos; |
|
||||||
|
|
||||||
public SignatureStream (byte[] signature) |
|
||||||
{ |
|
||||||
this.signature = signature; |
|
||||||
currentPos = 0; |
|
||||||
} |
|
||||||
|
|
||||||
public SignatureStream (IntPtr pSigBlob, uint sigBlobSize) |
|
||||||
{ |
|
||||||
signature = new Byte[sigBlobSize]; |
|
||||||
Marshal.Copy(pSigBlob, signature, 0, (int)sigBlobSize); |
|
||||||
currentPos = 0; |
|
||||||
} |
|
||||||
|
|
||||||
public bool EndOfStream { |
|
||||||
get { |
|
||||||
return currentPos >= signature.Length; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
byte PeekByte { |
|
||||||
get { |
|
||||||
if (EndOfStream) throw new BadSignatureException(); |
|
||||||
return signature[currentPos]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
byte ReadByte { |
|
||||||
get { |
|
||||||
byte value = PeekByte; |
|
||||||
currentPos++; |
|
||||||
return value; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
uint ReadData(out int compressedSize) |
|
||||||
{ |
|
||||||
if ((PeekByte & 0x80) == 0x00) { |
|
||||||
compressedSize = 1; |
|
||||||
return ReadByte; |
|
||||||
} |
|
||||||
if ((PeekByte & 0xC0) == 0x80) { |
|
||||||
compressedSize = 2; |
|
||||||
return (uint)( |
|
||||||
(ReadByte & 0x3F) * 0x100 + |
|
||||||
ReadByte |
|
||||||
); |
|
||||||
} |
|
||||||
if ((PeekByte & 0xE0) == 0xC0) { |
|
||||||
compressedSize = 4; |
|
||||||
return (uint)( |
|
||||||
(ReadByte & 0x1F) * 0x1000000 + |
|
||||||
ReadByte * 0x10000 + |
|
||||||
ReadByte * 0x100 + |
|
||||||
ReadByte |
|
||||||
); |
|
||||||
} |
|
||||||
throw new BadSignatureException(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public uint PeekData() |
|
||||||
{ |
|
||||||
int oldPos = currentPos; |
|
||||||
uint res = ReadData(); |
|
||||||
currentPos = oldPos; |
|
||||||
return res; |
|
||||||
} |
|
||||||
|
|
||||||
public uint ReadData() |
|
||||||
{ |
|
||||||
int compressedSize; |
|
||||||
return ReadData(out compressedSize); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
CorTokenType[] encodeTokenType = new CorTokenType[] {CorTokenType.mdtTypeDef, CorTokenType.mdtTypeRef, CorTokenType.mdtTypeSpec, CorTokenType.mdtBaseType}; |
|
||||||
|
|
||||||
public uint PeekToken() |
|
||||||
{ |
|
||||||
int oldPos = currentPos; |
|
||||||
uint res = ReadToken(); |
|
||||||
currentPos = oldPos; |
|
||||||
return res; |
|
||||||
} |
|
||||||
|
|
||||||
public uint ReadToken() |
|
||||||
{ |
|
||||||
uint data; |
|
||||||
uint tokenType; |
|
||||||
|
|
||||||
data = ReadData(); |
|
||||||
tokenType = (uint)encodeTokenType[data & 0x3]; |
|
||||||
return (data >> 2) | tokenType; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public uint PeekSignedInt() |
|
||||||
{ |
|
||||||
int oldPos = currentPos; |
|
||||||
uint res = ReadSignedInt(); |
|
||||||
currentPos = oldPos; |
|
||||||
return res; |
|
||||||
} |
|
||||||
|
|
||||||
public uint ReadSignedInt() |
|
||||||
{ |
|
||||||
int compressedSize; |
|
||||||
bool signed; |
|
||||||
uint data; |
|
||||||
|
|
||||||
data = ReadData(out compressedSize); |
|
||||||
signed = (data & 0x1) == 1; |
|
||||||
data = data >> 1; |
|
||||||
if (signed) { |
|
||||||
switch (compressedSize) { |
|
||||||
case 1: |
|
||||||
data |= 0xffffffc0; |
|
||||||
break; |
|
||||||
case 2: |
|
||||||
data |= 0xffffe000; |
|
||||||
break; |
|
||||||
case 4: |
|
||||||
data |= 0xf0000000; |
|
||||||
break; |
|
||||||
default: |
|
||||||
throw new BadSignatureException(); |
|
||||||
} |
|
||||||
} |
|
||||||
return data; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public uint PeekCallingConv() |
|
||||||
{ |
|
||||||
int oldPos = currentPos; |
|
||||||
uint res = ReadCallingConv(); |
|
||||||
currentPos = oldPos; |
|
||||||
return res; |
|
||||||
} |
|
||||||
|
|
||||||
public uint ReadCallingConv() |
|
||||||
{ |
|
||||||
return ReadData(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public CorElementType PeekElementType() |
|
||||||
{ |
|
||||||
int oldPos = currentPos; |
|
||||||
CorElementType res = ReadElementType(); |
|
||||||
currentPos = oldPos; |
|
||||||
return res; |
|
||||||
} |
|
||||||
|
|
||||||
public CorElementType ReadElementType() |
|
||||||
{ |
|
||||||
return (CorElementType)ReadData(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void ReadCustomMod() |
|
||||||
{ |
|
||||||
while (PeekElementType() == CorElementType.CMOD_OPT || |
|
||||||
PeekElementType() == CorElementType.CMOD_REQD) { |
|
||||||
ReadElementType(); |
|
||||||
ReadToken(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public string ReadType() |
|
||||||
{ |
|
||||||
CorElementType type = ReadElementType(); |
|
||||||
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: |
|
||||||
case CorElementType.OBJECT: |
|
||||||
return type.ToString(); |
|
||||||
|
|
||||||
case CorElementType.VALUETYPE: |
|
||||||
case CorElementType.CLASS: |
|
||||||
ReadToken(); |
|
||||||
return type.ToString(); |
|
||||||
|
|
||||||
case CorElementType.PTR: |
|
||||||
ReadCustomMod(); |
|
||||||
if (PeekElementType() == CorElementType.VOID) { |
|
||||||
ReadElementType(); |
|
||||||
break; |
|
||||||
} else { |
|
||||||
return "Pointer:" + ReadType(); |
|
||||||
} |
|
||||||
|
|
||||||
case CorElementType.FNPTR: |
|
||||||
ReadFunction(); |
|
||||||
break; |
|
||||||
|
|
||||||
case CorElementType.ARRAY: |
|
||||||
ReadType(); |
|
||||||
ReadArrayShape(); |
|
||||||
break; |
|
||||||
|
|
||||||
case CorElementType.SZARRAY: // Short-cut for single dimension zero lower bound array
|
|
||||||
ReadCustomMod(); |
|
||||||
ReadType(); |
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
throw new BadSignatureException(); |
|
||||||
} |
|
||||||
return ""; |
|
||||||
} |
|
||||||
|
|
||||||
public void ReadArrayShape() |
|
||||||
{ |
|
||||||
ReadData(); //rank
|
|
||||||
uint numSizes = ReadData(); |
|
||||||
for (int i = 0; i < numSizes; i++) { |
|
||||||
ReadData(); //size
|
|
||||||
} |
|
||||||
if (numSizes > 0) { |
|
||||||
uint numLoBounds = ReadData(); |
|
||||||
for (int i = 0; i < numLoBounds; i++) { |
|
||||||
ReadData(); //LoBound
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void ReadFunction() |
|
||||||
{ |
|
||||||
uint callConv = ReadCallingConv(); |
|
||||||
uint paramCount = ReadData(); |
|
||||||
|
|
||||||
// Read return type
|
|
||||||
switch (ReadElementType()) { |
|
||||||
case CorElementType.BYREF: |
|
||||||
ReadType(); |
|
||||||
break; |
|
||||||
case CorElementType.TYPEDBYREF: |
|
||||||
break; |
|
||||||
case CorElementType.VOID: |
|
||||||
break; |
|
||||||
default: |
|
||||||
throw new BadSignatureException(); |
|
||||||
} |
|
||||||
|
|
||||||
// Read params
|
|
||||||
for (int i = 0; i < paramCount; i++) { |
|
||||||
ReadCustomMod(); |
|
||||||
switch (PeekElementType()) { |
|
||||||
case CorElementType.BYREF: |
|
||||||
ReadElementType(); |
|
||||||
ReadType(); |
|
||||||
break; |
|
||||||
case CorElementType.TYPEDBYREF: |
|
||||||
ReadElementType(); |
|
||||||
break; |
|
||||||
default: |
|
||||||
ReadType(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,32 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2023 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
using Debugger.Wrappers.MetaData; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Binding flags specify which members should be returned.
|
||||||
|
/// <para> Use 'or' operation to combine flags. </para>
|
||||||
|
/// </summary>
|
||||||
|
[Flags] |
||||||
|
public enum BindingFlags { |
||||||
|
/// Return instance (ie non-static members) members
|
||||||
|
Instance, |
||||||
|
/// Return static members
|
||||||
|
Static, |
||||||
|
/// Return public members
|
||||||
|
Public, |
||||||
|
/// Return members which are not public
|
||||||
|
NonPublic, |
||||||
|
/// Return all members
|
||||||
|
All = Instance | Static | Public | NonPublic |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2023 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
using Debugger.Wrappers.MetaData; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
public partial class DebugType |
||||||
|
{ |
||||||
|
IList<T> FilterMemberInfo<T>(List<T> input, BindingFlags bindingFlags) where T:MemberInfo |
||||||
|
{ |
||||||
|
List<T> filtered = new List<T>(); |
||||||
|
foreach(T memberInfo in input) { |
||||||
|
if (memberInfo.IsStatic && ((bindingFlags & BindingFlags.Static) != 0) || |
||||||
|
!memberInfo.IsStatic && ((bindingFlags & BindingFlags.Instance) != 0)) { |
||||||
|
|
||||||
|
if (memberInfo.IsPrivate && ((bindingFlags & BindingFlags.NonPublic) != 0) || |
||||||
|
memberInfo.IsPublic && ((bindingFlags & BindingFlags.Public) != 0)) { |
||||||
|
|
||||||
|
filtered.Add(memberInfo); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return filtered.AsReadOnly(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns simple managed type coresponding to the debug type.
|
||||||
|
/// Any class yields System.Object
|
||||||
|
/// </summary>
|
||||||
|
public System.Type ManagedType { |
||||||
|
get { |
||||||
|
switch(this.corElementType) { |
||||||
|
case CorElementType.BOOLEAN: return typeof(System.Boolean); |
||||||
|
case CorElementType.CHAR: return typeof(System.Char); |
||||||
|
case CorElementType.I1: return typeof(System.SByte); |
||||||
|
case CorElementType.U1: return typeof(System.Byte); |
||||||
|
case CorElementType.I2: return typeof(System.Int16); |
||||||
|
case CorElementType.U2: return typeof(System.UInt16); |
||||||
|
case CorElementType.I4: return typeof(System.Int32); |
||||||
|
case CorElementType.U4: return typeof(System.UInt32); |
||||||
|
case CorElementType.I8: return typeof(System.Int64); |
||||||
|
case CorElementType.U8: return typeof(System.UInt64); |
||||||
|
case CorElementType.R4: return typeof(System.Single); |
||||||
|
case CorElementType.R8: return typeof(System.Double); |
||||||
|
case CorElementType.I: return typeof(int); |
||||||
|
case CorElementType.U: return typeof(uint); |
||||||
|
case CorElementType.SZARRAY: |
||||||
|
case CorElementType.ARRAY: return typeof(System.Array); |
||||||
|
case CorElementType.OBJECT: return typeof(System.Object); |
||||||
|
case CorElementType.STRING: return typeof(System.String); |
||||||
|
default: return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Find the super class manually - unused since we have ICorDebugType.GetBase() in .NET 2.0 |
||||||
|
* |
||||||
|
protected static ICorDebugClass GetSuperClass(Process process, ICorDebugClass currClass) |
||||||
|
{ |
||||||
|
Module currModule = process.GetModule(currClass.Module); |
||||||
|
uint superToken = currModule.MetaData.GetTypeDefProps(currClass.Token).SuperClassToken; |
||||||
|
|
||||||
|
// It has no base class
|
||||||
|
if ((superToken & 0x00FFFFFF) == 0x00000000) return null; |
||||||
|
|
||||||
|
// TypeDef - Localy defined
|
||||||
|
if ((superToken & 0xFF000000) == 0x02000000) { |
||||||
|
return currModule.CorModule.GetClassFromToken(superToken); |
||||||
|
} |
||||||
|
|
||||||
|
// TypeRef - Referencing to external assembly
|
||||||
|
if ((superToken & 0xFF000000) == 0x01000000) { |
||||||
|
string fullTypeName = currModule.MetaData.GetTypeRefProps(superToken).Name; |
||||||
|
|
||||||
|
foreach (Module superModule in process.Modules) { |
||||||
|
// TODO: Does not work for nested
|
||||||
|
// TODO: preservesig
|
||||||
|
try { |
||||||
|
uint token = superModule.MetaData.FindTypeDefByName(fullTypeName, 0).Token; |
||||||
|
return superModule.CorModule.GetClassFromToken(token); |
||||||
|
} catch { |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Can also be TypeSpec = 0x1b000000
|
||||||
|
|
||||||
|
throw new DebuggerException("Superclass not found"); |
||||||
|
} |
||||||
|
*/ |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,340 @@ |
|||||||
|
// <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; |
||||||
|
using Debugger.Wrappers.MetaData; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents a type in a debugee. That is, a class, array, value type or a primitive type.
|
||||||
|
/// <para> This class mimics the <see cref="System.Type"/> class. </para>
|
||||||
|
/// </summary>
|
||||||
|
public partial class DebugType: RemotingObjectBase |
||||||
|
{ |
||||||
|
Process process; |
||||||
|
ICorDebugType corType; |
||||||
|
CorElementType corElementType; |
||||||
|
|
||||||
|
// Class/ValueType specific data
|
||||||
|
ICorDebugClass corClass; |
||||||
|
Module module; |
||||||
|
TypeDefProps classProps; |
||||||
|
|
||||||
|
// Cache
|
||||||
|
List<FieldInfo> fields; |
||||||
|
List<MethodInfo> methods; |
||||||
|
List<PropertyInfo> properties; |
||||||
|
|
||||||
|
void AssertClassOrValueType() |
||||||
|
{ |
||||||
|
if(!IsClass && !IsValueType) { |
||||||
|
throw new DebuggerException("The type is not a class or value type."); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets the process in which the type was loaded </summary>
|
||||||
|
public Process Process { |
||||||
|
get { |
||||||
|
return process; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal ICorDebugType CorType { |
||||||
|
get { |
||||||
|
return corType; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the module in which the class or value type is defined.
|
||||||
|
/// <para> Only applicable to class or value type! </para>
|
||||||
|
/// </summary>
|
||||||
|
public Module Module { |
||||||
|
get { |
||||||
|
AssertClassOrValueType(); |
||||||
|
return module; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the metadata token of the class or value type.
|
||||||
|
/// <para> Only applicable to class or value type! </para>
|
||||||
|
/// </summary>
|
||||||
|
public uint MetadataToken { |
||||||
|
get { |
||||||
|
AssertClassOrValueType(); |
||||||
|
return classProps.Token; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns a string describing the type </summary>
|
||||||
|
public string Name { |
||||||
|
get { |
||||||
|
// TODO: Improve
|
||||||
|
if(IsClass || IsValueType) { |
||||||
|
return classProps.Name; |
||||||
|
} else { |
||||||
|
System.Type managedType = this.ManagedType; |
||||||
|
if (managedType != null) { |
||||||
|
return managedType.ToString(); |
||||||
|
} else { |
||||||
|
return "<unknown>"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether the type is an array </summary>
|
||||||
|
public bool IsArray { |
||||||
|
get { |
||||||
|
return this.corElementType == CorElementType.ARRAY || |
||||||
|
this.corElementType == CorElementType.SZARRAY; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether the type is a class </summary>
|
||||||
|
public bool IsClass { |
||||||
|
get { |
||||||
|
return this.corElementType == CorElementType.CLASS || |
||||||
|
this.corElementType == CorElementType.OBJECT; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether the type is a value type (that is, a structre in C#) </summary>
|
||||||
|
public bool IsValueType { |
||||||
|
get { |
||||||
|
return this.corElementType == CorElementType.VALUETYPE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether the type is a primitive type </summary>
|
||||||
|
public bool IsPrimitive { |
||||||
|
get { |
||||||
|
return this.corElementType == CorElementType.BOOLEAN || |
||||||
|
this.corElementType == CorElementType.CHAR || |
||||||
|
this.corElementType == CorElementType.I1 || |
||||||
|
this.corElementType == CorElementType.U1 || |
||||||
|
this.corElementType == CorElementType.I2 || |
||||||
|
this.corElementType == CorElementType.U2 || |
||||||
|
this.corElementType == CorElementType.I4 || |
||||||
|
this.corElementType == CorElementType.U4 || |
||||||
|
this.corElementType == CorElementType.I8 || |
||||||
|
this.corElementType == CorElementType.U8 || |
||||||
|
this.corElementType == CorElementType.R4 || |
||||||
|
this.corElementType == CorElementType.R8 || |
||||||
|
this.corElementType == CorElementType.I || |
||||||
|
this.corElementType == CorElementType.U || |
||||||
|
this.corElementType == CorElementType.STRING; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether the type is an integer type </summary>
|
||||||
|
public bool IsInteger { |
||||||
|
get { |
||||||
|
return this.corElementType == CorElementType.I1 || |
||||||
|
this.corElementType == CorElementType.U1 || |
||||||
|
this.corElementType == CorElementType.I2 || |
||||||
|
this.corElementType == CorElementType.U2 || |
||||||
|
this.corElementType == CorElementType.I4 || |
||||||
|
this.corElementType == CorElementType.U4 || |
||||||
|
this.corElementType == CorElementType.I8 || |
||||||
|
this.corElementType == CorElementType.U8 || |
||||||
|
this.corElementType == CorElementType.I || |
||||||
|
this.corElementType == CorElementType.U; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type from which this type inherits.
|
||||||
|
/// <para>
|
||||||
|
/// Returns null if the current type is <see cref="System.Object"/>.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
public DebugType BaseType { |
||||||
|
get { |
||||||
|
ICorDebugType baseType = corType.Base; |
||||||
|
if (baseType != null) { |
||||||
|
return new DebugType(process, baseType); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal DebugType(Process process, ICorDebugType corType) |
||||||
|
{ |
||||||
|
if (corType == null) throw new ArgumentNullException("corType"); |
||||||
|
|
||||||
|
this.process = process; |
||||||
|
this.corType = corType; |
||||||
|
this.corElementType = (CorElementType)corType.Type; |
||||||
|
|
||||||
|
if (this.IsClass || this.IsValueType) { |
||||||
|
this.corClass = corType.Class; |
||||||
|
this.module = process.GetModule(corClass.Module); |
||||||
|
this.classProps = module.MetaData.GetTypeDefProps(corClass.Token); |
||||||
|
} |
||||||
|
|
||||||
|
process.TraceMessage("Created type " + this.Name); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Obtains instance of DebugType using process cache
|
||||||
|
/// </summary>
|
||||||
|
static internal DebugType Create(Process process, ICorDebugType corType) |
||||||
|
{ |
||||||
|
return process.GetDebugType(corType); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Determines whether the current type is sublass of
|
||||||
|
/// the the given type. That is, it derives from the given type. </summary>
|
||||||
|
/// <remarks> Returns false if the given type is same as the current type </remarks>
|
||||||
|
public bool IsSubclassOf(DebugType superType) |
||||||
|
{ |
||||||
|
DebugType type = this.BaseType; |
||||||
|
while (type != null) { |
||||||
|
if (this.Equals(type)) return true; |
||||||
|
type = type.BaseType; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Determines whether the given object is instance of the
|
||||||
|
/// current type or can be implicitly cast to it </summary>
|
||||||
|
public bool IsInstanceOfType(Value objectInstance) |
||||||
|
{ |
||||||
|
return this.Equals(objectInstance.Type) || |
||||||
|
this.IsSubclassOf(objectInstance.Type); |
||||||
|
} |
||||||
|
|
||||||
|
List<FieldInfo> GetAllFields() |
||||||
|
{ |
||||||
|
AssertClassOrValueType(); |
||||||
|
|
||||||
|
// Build cache
|
||||||
|
if (fields == null) { |
||||||
|
process.TraceMessage("Loading fields for type " + this.Name); |
||||||
|
fields = new List<FieldInfo>(); |
||||||
|
foreach(FieldProps field in module.MetaData.EnumFields(this.MetadataToken)) { |
||||||
|
// TODO: Why?
|
||||||
|
if (field.IsStatic && field.IsLiteral) continue; // Skip static literals
|
||||||
|
fields.Add(new FieldInfo(this, field)); |
||||||
|
}; |
||||||
|
} |
||||||
|
return fields; |
||||||
|
} |
||||||
|
|
||||||
|
List<MethodInfo> GetAllMethods() |
||||||
|
{ |
||||||
|
AssertClassOrValueType(); |
||||||
|
|
||||||
|
// Build cache
|
||||||
|
if (methods == null) { |
||||||
|
process.TraceMessage("Loading methods for type " + this.Name); |
||||||
|
methods = new List<MethodInfo>(); |
||||||
|
foreach(MethodProps m in module.MetaData.EnumMethods(this.MetadataToken)) { |
||||||
|
methods.Add(new MethodInfo(this, m)); |
||||||
|
} |
||||||
|
} |
||||||
|
return methods; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Handle indexers ("get_Item") in other code
|
||||||
|
List<PropertyInfo> GetAllProperties() |
||||||
|
{ |
||||||
|
AssertClassOrValueType(); |
||||||
|
|
||||||
|
// Build cache
|
||||||
|
if (properties == null) { |
||||||
|
process.TraceMessage("Loading properties for type " + this.Name); |
||||||
|
properties = new List<PropertyInfo>(); |
||||||
|
// Collect data
|
||||||
|
Dictionary<string, MethodInfo> methods = new Dictionary<string, MethodInfo>(); |
||||||
|
Dictionary<string, object> names = new Dictionary<string, object>(); |
||||||
|
foreach(MethodInfo method in GetAllMethods()) { |
||||||
|
if (method.IsSpecialName && (method.Name.StartsWith("get_") || method.Name.StartsWith("set_"))) { |
||||||
|
methods.Add(method.Name, method); |
||||||
|
names.Add(method.Name.Remove(0,4), null); |
||||||
|
} |
||||||
|
} |
||||||
|
// Pair up getters and setters
|
||||||
|
foreach(KeyValuePair<string, object> kvp in names) { |
||||||
|
MethodInfo getter = null; |
||||||
|
MethodInfo setter = null; |
||||||
|
methods.TryGetValue("get_" + kvp.Key, out getter); |
||||||
|
methods.TryGetValue("set_" + kvp.Key, out setter); |
||||||
|
properties.Add(new PropertyInfo(this, getter, setter)); |
||||||
|
} |
||||||
|
} |
||||||
|
return properties; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Return all public fields.</summary>
|
||||||
|
public IList<FieldInfo> GetFields() |
||||||
|
{ |
||||||
|
return GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Return all fields satisfing binding flags.</summary>
|
||||||
|
public IList<FieldInfo> GetFields(BindingFlags bindingFlags) |
||||||
|
{ |
||||||
|
if (IsClass || IsValueType) { |
||||||
|
return FilterMemberInfo(GetAllFields(), bindingFlags); |
||||||
|
} else { |
||||||
|
return new List<FieldInfo>(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Return all public methods.</summary>
|
||||||
|
public IList<MethodInfo> GetMethods() |
||||||
|
{ |
||||||
|
return GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Return all methods satisfing binding flags.</summary>
|
||||||
|
public IList<MethodInfo> GetMethods(BindingFlags bindingFlags) |
||||||
|
{ |
||||||
|
if (IsClass || IsValueType) { |
||||||
|
return FilterMemberInfo(GetAllMethods(), bindingFlags); |
||||||
|
} else { |
||||||
|
return new List<MethodInfo>(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Return all public properties.</summary>
|
||||||
|
public IList<PropertyInfo> GetProperties() |
||||||
|
{ |
||||||
|
return GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Return all properties satisfing binding flags.</summary>
|
||||||
|
public IList<PropertyInfo> GetProperties(BindingFlags bindingFlags) |
||||||
|
{ |
||||||
|
if (IsClass || IsValueType) { |
||||||
|
return FilterMemberInfo(GetAllProperties(), bindingFlags); |
||||||
|
} else { |
||||||
|
return new List<PropertyInfo>(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Compares two types </summary>
|
||||||
|
public override bool Equals(object obj) |
||||||
|
{ |
||||||
|
return obj is DebugType && |
||||||
|
((DebugType)obj).CorType == this.CorType; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Get hash code of the object </summary>
|
||||||
|
public override int GetHashCode() |
||||||
|
{ |
||||||
|
return base.GetHashCode(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,109 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2023 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
using Debugger.Wrappers.MetaData; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Provides information about a field of some class.
|
||||||
|
/// </summary>
|
||||||
|
public class FieldInfo: MemberInfo |
||||||
|
{ |
||||||
|
FieldProps fieldProps; |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this field is literal field </summary>
|
||||||
|
public bool IsLiteral { |
||||||
|
get { |
||||||
|
return fieldProps.IsLiteral; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this field is private </summary>
|
||||||
|
public override bool IsPrivate { |
||||||
|
get { |
||||||
|
return !fieldProps.IsPublic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this field is public </summary>
|
||||||
|
public override bool IsPublic { |
||||||
|
get { |
||||||
|
return fieldProps.IsPublic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this field is static </summary>
|
||||||
|
public override bool IsStatic { |
||||||
|
get { |
||||||
|
return fieldProps.IsStatic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets the metadata token associated with this field </summary>
|
||||||
|
public override uint MetadataToken { |
||||||
|
get { |
||||||
|
return fieldProps.Token; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets the name of this field </summary>
|
||||||
|
public override string Name { |
||||||
|
get { |
||||||
|
return fieldProps.Name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal FieldInfo(DebugType declaringType, FieldProps fieldProps):base (declaringType) |
||||||
|
{ |
||||||
|
this.fieldProps = fieldProps; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given an object of correct type, get the value of this field
|
||||||
|
/// </summary>
|
||||||
|
public MemberValue GetValue(Value objectInstance) { |
||||||
|
return new MemberValue( |
||||||
|
this, |
||||||
|
this.Process, |
||||||
|
new IExpirable[] {objectInstance}, |
||||||
|
new IMutable[] {objectInstance}, |
||||||
|
delegate { return GetCorValue(objectInstance); } |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
ICorDebugValue GetCorValue(Value objectInstance) |
||||||
|
{ |
||||||
|
if (!DeclaringType.IsInstanceOfType(objectInstance)) { |
||||||
|
throw new CannotGetValueException("Object is not of type " + DeclaringType.Name); |
||||||
|
} |
||||||
|
|
||||||
|
// Current frame is used to resolve context specific static values (eg. ThreadStatic)
|
||||||
|
ICorDebugFrame curFrame = null; |
||||||
|
if (this.Process.IsPaused && |
||||||
|
this.Process.SelectedThread != null && |
||||||
|
this.Process.SelectedThread.LastFunction != null && |
||||||
|
this.Process.SelectedThread.LastFunction.CorILFrame != null) { |
||||||
|
|
||||||
|
curFrame = this.Process.SelectedThread.LastFunction.CorILFrame.CastTo<ICorDebugFrame>(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
if (this.IsStatic) { |
||||||
|
return DeclaringType.CorType.GetStaticFieldValue(MetadataToken, curFrame); |
||||||
|
} else { |
||||||
|
return objectInstance.CorObjectValue.GetFieldValue(DeclaringType.CorType.Class, MetadataToken); |
||||||
|
} |
||||||
|
} catch { |
||||||
|
throw new CannotGetValueException("Can not get value of field"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2023 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
using Debugger.Wrappers.MetaData; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Provides information about a member of some class
|
||||||
|
/// (eg. a field or a method).
|
||||||
|
/// </summary>
|
||||||
|
public abstract class MemberInfo: RemotingObjectBase |
||||||
|
{ |
||||||
|
DebugType declaringType; |
||||||
|
|
||||||
|
/// <summary> Gets the process in which the type was loaded </summary>
|
||||||
|
public Process Process { |
||||||
|
get { |
||||||
|
return declaringType.Process; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets the type that declares this member element </summary>
|
||||||
|
public DebugType DeclaringType { |
||||||
|
get { |
||||||
|
return declaringType; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this member is private </summary>
|
||||||
|
public abstract bool IsPrivate { get; } |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this member is public </summary>
|
||||||
|
public abstract bool IsPublic { get; } |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this member is static </summary>
|
||||||
|
public abstract bool IsStatic { get; } |
||||||
|
|
||||||
|
/// <summary> Gets the metadata token associated with this member </summary>
|
||||||
|
public abstract uint MetadataToken { get; } |
||||||
|
|
||||||
|
/// <summary> Gets the name of this member </summary>
|
||||||
|
public abstract string Name { get; } |
||||||
|
|
||||||
|
/// <summary> Gets the module in which this member is defined </summary>
|
||||||
|
public Module Module { |
||||||
|
get { |
||||||
|
return declaringType.Module; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal MemberInfo(DebugType declaringType) |
||||||
|
{ |
||||||
|
this.declaringType = declaringType; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,126 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2023 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
using Debugger.Wrappers.MetaData; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Provides information about a method in a class
|
||||||
|
/// </summary>
|
||||||
|
public class MethodInfo: MemberInfo |
||||||
|
{ |
||||||
|
MethodProps methodProps; |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this method is private </summary>
|
||||||
|
public override bool IsPrivate { |
||||||
|
get { |
||||||
|
return !methodProps.IsPublic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this method is public </summary>
|
||||||
|
public override bool IsPublic { |
||||||
|
get { |
||||||
|
return methodProps.IsPublic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether the name of this method
|
||||||
|
/// is marked as specail.</summary>
|
||||||
|
/// <remarks> For example, property accessors are marked as special </remarks>
|
||||||
|
public bool IsSpecialName { |
||||||
|
get { |
||||||
|
return methodProps.HasSpecialName; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this method is static </summary>
|
||||||
|
public override bool IsStatic { |
||||||
|
get { |
||||||
|
return methodProps.IsStatic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets the metadata token associated with this method </summary>
|
||||||
|
public override uint MetadataToken { |
||||||
|
get { |
||||||
|
return methodProps.Token; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets the name of this method </summary>
|
||||||
|
public override string Name { |
||||||
|
get { |
||||||
|
return methodProps.Name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal ICorDebugFunction CorFunction { |
||||||
|
get { |
||||||
|
return this.Module.CorModule.GetFunctionFromToken(this.MetadataToken); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal MethodInfo(DebugType declaringType, MethodProps methodProps):base (declaringType) |
||||||
|
{ |
||||||
|
this.methodProps = methodProps; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a method from a managed type, method name and argument count
|
||||||
|
/// </summary>
|
||||||
|
public static MethodInfo GetFromName(Process process, System.Type type, string name, int paramCount) |
||||||
|
{ |
||||||
|
if (type.IsNested) throw new DebuggerException("Not implemented for nested types"); |
||||||
|
if (type.IsGenericType) throw new DebuggerException("Not implemented for generic types"); |
||||||
|
if (type.IsGenericParameter) throw new DebuggerException("Type can not be generic parameter"); |
||||||
|
|
||||||
|
foreach(Module module in process.Modules) { |
||||||
|
TypeDefProps typeDefProps = module.MetaData.FindTypeDefByName(type.FullName, 0 /* enclosing class for nested */); |
||||||
|
foreach(MethodProps methodProps in module.MetaData.EnumMethodsWithName(typeDefProps.Token, name)) { |
||||||
|
if (module.MetaData.GetParamCount(methodProps.Token) == paramCount) { |
||||||
|
ICorDebugFunction corFunction = module.CorModule.GetFunctionFromToken(methodProps.Token); |
||||||
|
ICorDebugClass2 corClass = corFunction.Class.As<ICorDebugClass2>(); |
||||||
|
ICorDebugType corType = corClass.GetParameterizedType(type.IsValueType ? (uint)CorElementType.VALUETYPE : (uint)CorElementType.CLASS, |
||||||
|
0, |
||||||
|
new ICorDebugType[] {}); |
||||||
|
return new MethodInfo(DebugType.Create(process, corType), methodProps); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
throw new DebuggerException("Not found"); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synchronously invoke the method of an a given object
|
||||||
|
/// </summary>
|
||||||
|
public Value Invoke(Value objectInstance, Value[] arguments) |
||||||
|
{ |
||||||
|
return Eval.InvokeMethod( |
||||||
|
this, |
||||||
|
this.IsStatic ? null : objectInstance, |
||||||
|
arguments ?? new Value[0] |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously invoke the method of an a given object
|
||||||
|
/// </summary>
|
||||||
|
public Eval AsyncInvoke(Value objectInstance, Value[] arguments) |
||||||
|
{ |
||||||
|
return Eval.AsyncInvokeMethod( |
||||||
|
this, |
||||||
|
this.IsStatic ? null : objectInstance, |
||||||
|
arguments ?? new Value[0] |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,120 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2023 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
using Debugger.Wrappers.MetaData; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Provides information about a property in a class
|
||||||
|
/// </summary>
|
||||||
|
public class PropertyInfo: MemberInfo |
||||||
|
{ |
||||||
|
MethodInfo getMethod; |
||||||
|
MethodInfo setMethod; |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this property is private </summary>
|
||||||
|
public override bool IsPrivate { |
||||||
|
get { |
||||||
|
return !(getMethod ?? setMethod).IsPublic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this property is public </summary>
|
||||||
|
public override bool IsPublic { |
||||||
|
get { |
||||||
|
return (getMethod ?? setMethod).IsPublic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this property is static </summary>
|
||||||
|
public override bool IsStatic { |
||||||
|
get { |
||||||
|
return (getMethod ?? setMethod).IsStatic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets the metadata token associated with getter (or setter)
|
||||||
|
/// of this property </summary>
|
||||||
|
public override uint MetadataToken { |
||||||
|
get { |
||||||
|
return (getMethod ?? setMethod).MetadataToken; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets the name of this property </summary>
|
||||||
|
public override string Name { |
||||||
|
get { |
||||||
|
return (getMethod ?? setMethod).Name.Remove(0,4); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal PropertyInfo(DebugType declaringType, MethodInfo getMethod, MethodInfo setMethod): base(declaringType) |
||||||
|
{ |
||||||
|
if (getMethod == null && setMethod == null) throw new ArgumentNullException("Both getter and setter can not be null."); |
||||||
|
|
||||||
|
this.getMethod = getMethod; |
||||||
|
this.setMethod = setMethod; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Get the get accessor of the property </summary>
|
||||||
|
public MethodInfo GetGetMethod() |
||||||
|
{ |
||||||
|
return getMethod; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Get the set accessor of the property </summary>
|
||||||
|
public MethodInfo GetSetMethod() |
||||||
|
{ |
||||||
|
return setMethod; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Get the value of the property using the get accessor </summary>
|
||||||
|
public MemberValue GetValue(Value objectInstance) |
||||||
|
{ |
||||||
|
return GetValue(objectInstance, null); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Get the value of indexer property </summary>
|
||||||
|
public MemberValue GetValue(Value objectInstance, Value[] parameters) |
||||||
|
{ |
||||||
|
if (getMethod == null) throw new CannotGetValueException("Property does not have a get method"); |
||||||
|
|
||||||
|
Value returnedValue = getMethod.Invoke(objectInstance, parameters ?? new Value[0]); |
||||||
|
|
||||||
|
return new MemberValue( |
||||||
|
this, |
||||||
|
this.Process, |
||||||
|
new IExpirable[] {returnedValue}, |
||||||
|
new IMutable[] {returnedValue}, |
||||||
|
delegate { return returnedValue.CorValue; } |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Set the value of the property using the set accessor </summary>
|
||||||
|
public Value SetValue(Value objectInstance, Value newValue) |
||||||
|
{ |
||||||
|
return SetValue(objectInstance, newValue, null); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Set the value of indexer property </summary>
|
||||||
|
public Value SetValue(Value objectInstance, Value newValue, Value[] parameters) |
||||||
|
{ |
||||||
|
if (setMethod == null) throw new CannotGetValueException("Property does not have a set method"); |
||||||
|
|
||||||
|
parameters = parameters ?? new Value[0]; |
||||||
|
Value[] allParams = new Value[1 + parameters.Length]; |
||||||
|
allParams[0] = newValue; |
||||||
|
parameters.CopyTo(allParams, 1); |
||||||
|
|
||||||
|
return setMethod.Invoke(objectInstance, allParams); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,38 +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; |
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
public class UnavailableValue: ValueProxy |
|
||||||
{ |
|
||||||
string message; |
|
||||||
|
|
||||||
public override string AsString { |
|
||||||
get { |
|
||||||
return message; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override string Type { |
|
||||||
get { |
|
||||||
return String.Empty; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal UnavailableValue(Value @value, string message):base(@value) |
|
||||||
{ |
|
||||||
this.message = message; |
|
||||||
} |
|
||||||
|
|
||||||
protected override bool GetMayHaveSubVariables() |
|
||||||
{ |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,446 +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>
|
|
||||||
/// 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 |
|
||||||
{ |
|
||||||
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 process; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ICorDebugValue CorValue { |
|
||||||
get { |
|
||||||
return DereferenceUnbox(RawCorValue); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal CorElementType CorType { |
|
||||||
get { |
|
||||||
return GetCorType(this.CorValue); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal static CorElementType GetCorType(ICorDebugValue corValue) |
|
||||||
{ |
|
||||||
if (corValue == null) { |
|
||||||
return (CorElementType)0; |
|
||||||
} |
|
||||||
return (CorElementType)corValue.Type; |
|
||||||
} |
|
||||||
|
|
||||||
protected virtual ICorDebugValue RawCorValue { |
|
||||||
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; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ValueProxy ValueProxy { |
|
||||||
get { |
|
||||||
if (currentValue == null) { |
|
||||||
try { |
|
||||||
currentValue = CreateValue(); |
|
||||||
} catch (CannotGetValueException e) { |
|
||||||
currentValue = new UnavailableValue(this, e.Message); |
|
||||||
} |
|
||||||
} |
|
||||||
return currentValue; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
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
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
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; |
|
||||||
} |
|
||||||
|
|
||||||
void AddExpireDependency(IExpirable dependency) |
|
||||||
{ |
|
||||||
if (dependency.HasExpired) { |
|
||||||
MakeExpired(); |
|
||||||
} else { |
|
||||||
dependency.Expired += delegate { MakeExpired(); }; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void AddMutateDependency(IMutable dependency) |
|
||||||
{ |
|
||||||
dependency.Changed += DependencyChanged; |
|
||||||
} |
|
||||||
|
|
||||||
void MakeExpired() |
|
||||||
{ |
|
||||||
if (!isExpired) { |
|
||||||
isExpired = true; |
|
||||||
OnExpired(new ValueEventArgs(this)); |
|
||||||
foreach(IMutable mut in mutateDependencies) { |
|
||||||
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) |
|
||||||
{ |
|
||||||
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 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; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
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) |
|
||||||
{ |
|
||||||
case CorElementType.BOOLEAN: return typeof(System.Boolean); |
|
||||||
case CorElementType.CHAR: return typeof(System.Char); |
|
||||||
case CorElementType.I1: return typeof(System.SByte); |
|
||||||
case CorElementType.U1: return typeof(System.Byte); |
|
||||||
case CorElementType.I2: return typeof(System.Int16); |
|
||||||
case CorElementType.U2: return typeof(System.UInt16); |
|
||||||
case CorElementType.I4: return typeof(System.Int32); |
|
||||||
case CorElementType.U4: return typeof(System.UInt32); |
|
||||||
case CorElementType.I8: return typeof(System.Int64); |
|
||||||
case CorElementType.U8: return typeof(System.UInt64); |
|
||||||
case CorElementType.R4: return typeof(System.Single); |
|
||||||
case CorElementType.R8: return typeof(System.Double); |
|
||||||
case CorElementType.I: return typeof(int); |
|
||||||
case CorElementType.U: return typeof(uint); |
|
||||||
case CorElementType.SZARRAY: |
|
||||||
case CorElementType.ARRAY: return typeof(System.Array); |
|
||||||
case CorElementType.OBJECT: return typeof(System.Object); |
|
||||||
case CorElementType.STRING: return typeof(System.String); |
|
||||||
default: return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal static string CorTypeToString(CorElementType corType) |
|
||||||
{ |
|
||||||
Type manType = CorTypeToManagedType(corType); |
|
||||||
if (manType == null) return "<unknown>"; |
|
||||||
return manType.ToString(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
class CannotGetValueException: System.Exception |
|
||||||
{ |
|
||||||
public CannotGetValueException(string message):base(message) |
|
||||||
{ |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,93 +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 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; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,51 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2022 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// NamedValue is a Value which has some name associated with it -
|
||||||
|
/// eg the name of the field that holds the value.
|
||||||
|
/// </summary>
|
||||||
|
public class NamedValue: Value |
||||||
|
{ |
||||||
|
string name; |
||||||
|
|
||||||
|
/// <summary> Gets the name associated with the value </summary>
|
||||||
|
public string Name { |
||||||
|
get { |
||||||
|
return name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal NamedValue(string name, |
||||||
|
Process process, |
||||||
|
IExpirable[] expireDependencies, |
||||||
|
IMutable[] mutateDependencies, |
||||||
|
CorValueGetter corValueGetter) |
||||||
|
:base (process, |
||||||
|
expireDependencies, |
||||||
|
mutateDependencies, |
||||||
|
corValueGetter) |
||||||
|
{ |
||||||
|
this.name = name; |
||||||
|
|
||||||
|
// TODO: clean up
|
||||||
|
if (name.StartsWith("<") && name.Contains(">") && name != "<Base class>") { |
||||||
|
string middle = name.TrimStart('<').Split('>')[0]; // Get text between '<' and '>'
|
||||||
|
if (middle != "") { |
||||||
|
this.name = middle; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
// <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; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// An enumerable collection of values accessible by name.
|
||||||
|
/// </summary>
|
||||||
|
public class NamedValueCollection: RemotingObjectBase, IEnumerable<NamedValue>, IEnumerable |
||||||
|
{ |
||||||
|
internal static NamedValueCollection Empty = new NamedValueCollection(new NamedValue[0]); |
||||||
|
|
||||||
|
Dictionary<string, List<NamedValue>> collection = new Dictionary<string, List<NamedValue>>(); |
||||||
|
|
||||||
|
IEnumerator<NamedValue> IEnumerable<NamedValue>.GetEnumerator() |
||||||
|
{ |
||||||
|
foreach(KeyValuePair<string, List<NamedValue>> kvp in collection) { |
||||||
|
foreach(NamedValue namedValue in kvp.Value) { |
||||||
|
yield return namedValue; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() |
||||||
|
{ |
||||||
|
return ((IEnumerable<NamedValue>)this).GetEnumerator(); |
||||||
|
} |
||||||
|
|
||||||
|
internal NamedValueCollection(IEnumerable<NamedValue> namedValues) |
||||||
|
{ |
||||||
|
foreach(NamedValue namedValue in namedValues) { |
||||||
|
string name = namedValue.Name; |
||||||
|
if (collection.ContainsKey(name)) { |
||||||
|
collection[name].Add(namedValue); |
||||||
|
} else { |
||||||
|
collection[name] = new List<NamedValue>(new NamedValue[] {namedValue}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value by its name.
|
||||||
|
/// </summary>
|
||||||
|
public virtual NamedValue this[string variableName] { |
||||||
|
get { |
||||||
|
if (collection.ContainsKey(variableName)) { |
||||||
|
foreach(NamedValue namedValue in collection[variableName]) { |
||||||
|
return namedValue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// int index = variableName.IndexOf('.');
|
||||||
|
// if (index != -1) {
|
||||||
|
// string rootVariable = variableName.Substring(0, index);
|
||||||
|
// string subVariable = variableName.Substring(index + 1);
|
||||||
|
// return this[rootVariable].Value.SubVariables[subVariable];
|
||||||
|
// }
|
||||||
|
|
||||||
|
throw new DebuggerException("Variable \"" + variableName + "\" is not in collection"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,131 @@ |
|||||||
|
// <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; |
||||||
|
|
||||||
|
//TODO: Support for lower bound
|
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
// This part of the class provides support for arrays
|
||||||
|
public partial class Value |
||||||
|
{ |
||||||
|
ICorDebugArrayValue CorArrayValue { |
||||||
|
get { |
||||||
|
if (IsArray) { |
||||||
|
return CorValue.CastTo<ICorDebugArrayValue>(); |
||||||
|
} else { |
||||||
|
throw new DebuggerException("Value is not an array"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns true if the value is an array </summary>
|
||||||
|
public bool IsArray { |
||||||
|
get { |
||||||
|
return !IsNull && this.Type.IsArray; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of elements the array can store.
|
||||||
|
/// eg new object[4,5] returns 20
|
||||||
|
/// </summary>
|
||||||
|
public uint ArrayLenght { |
||||||
|
get { |
||||||
|
return CorArrayValue.Count; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of dimensions of the array.
|
||||||
|
/// eg new object[4,5] returns 2
|
||||||
|
/// </summary>
|
||||||
|
public uint ArrayRank { |
||||||
|
get { |
||||||
|
return CorArrayValue.Rank; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the lengths of individual dimensions.
|
||||||
|
/// eg new object[4,5] returns {4,5};
|
||||||
|
/// </summary>
|
||||||
|
public uint[] ArrayDimensions { |
||||||
|
get { |
||||||
|
return CorArrayValue.Dimensions; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns an element of a single-dimensional array </summary>
|
||||||
|
public ArrayElement GetArrayElement(uint index) |
||||||
|
{ |
||||||
|
return GetArrayElement(new uint[] {index}); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns an element of an array </summary>
|
||||||
|
public ArrayElement GetArrayElement(uint[] elementIndices) |
||||||
|
{ |
||||||
|
uint[] indices = (uint[])elementIndices.Clone(); |
||||||
|
|
||||||
|
return new ArrayElement( |
||||||
|
indices, |
||||||
|
Process, |
||||||
|
new IExpirable[] {this}, |
||||||
|
new IMutable[] {this}, |
||||||
|
delegate { return GetCorValueOfArrayElement(indices); } |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// May be called later
|
||||||
|
ICorDebugValue GetCorValueOfArrayElement(uint[] indices) |
||||||
|
{ |
||||||
|
if (!IsArray) { |
||||||
|
throw new CannotGetValueException("The value is not an array"); |
||||||
|
} |
||||||
|
if (indices.Length != ArrayRank) { |
||||||
|
throw new CannotGetValueException("Given indicies do not have the same dimension as array."); |
||||||
|
} |
||||||
|
for (int i = 0; i < indices.Length; i++) { |
||||||
|
if (indices[i] > ArrayDimensions[i]) { |
||||||
|
throw new CannotGetValueException("Given indices are out of range of the array"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return CorArrayValue.GetElement(indices); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns all elements in the array </summary>
|
||||||
|
public NamedValueCollection GetArrayElements() |
||||||
|
{ |
||||||
|
return new NamedValueCollection(GetArrayElementsEnum()); |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerable<NamedValue> GetArrayElementsEnum() |
||||||
|
{ |
||||||
|
uint[] indices = new uint[ArrayRank]; |
||||||
|
uint rank = ArrayRank; |
||||||
|
uint[] dimensions = ArrayDimensions; |
||||||
|
|
||||||
|
while(true) { // Go thought all combinations
|
||||||
|
for (uint i = rank - 1; i >= 1; i--) { |
||||||
|
if (indices[i] >= dimensions[i]) { |
||||||
|
indices[i] = 0; |
||||||
|
indices[i-1]++; |
||||||
|
} |
||||||
|
} |
||||||
|
if (indices[0] >= dimensions[0]) break; // We are done
|
||||||
|
|
||||||
|
yield return GetArrayElement(indices); |
||||||
|
|
||||||
|
indices[rank - 1]++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
// <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 partial class Value |
||||||
|
{ |
||||||
|
/// <summary> Returns true if the value is null </summary>
|
||||||
|
public bool IsNull { |
||||||
|
get { |
||||||
|
return CorValue == null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a string representation of the value </summary>
|
||||||
|
public string AsString { |
||||||
|
get { |
||||||
|
if (IsNull) return "<null reference>"; |
||||||
|
if (IsArray) return "{" + this.Type.Name + "}"; |
||||||
|
if (IsObject) return "{" + this.Type.Name + "}"; |
||||||
|
if (IsPrimitive) return PrimitiveValue != null ? PrimitiveValue.ToString() : String.Empty; |
||||||
|
throw new DebuggerException("Unknown value type"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// public bool MayHaveSubVariables {
|
||||||
|
// get {
|
||||||
|
// #if DEBUG
|
||||||
|
// if (IsNull) return true;
|
||||||
|
// if (IsArray) return true;
|
||||||
|
// if (IsObject) return true;
|
||||||
|
// if (IsPrimitive) return true;
|
||||||
|
// #else
|
||||||
|
// if (IsNull) return false;
|
||||||
|
// if (IsArray) return true;
|
||||||
|
// if (IsObject) return true;
|
||||||
|
// if (IsPrimitive) return false;
|
||||||
|
// #endif
|
||||||
|
// throw new DebuggerException("Unknown value type");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public VariableCollection SubVariables {
|
||||||
|
// get {
|
||||||
|
// VariableCollection subVars = null;
|
||||||
|
// if (IsNull) subVars = new VariableCollection(new Variable[] {});
|
||||||
|
// if (IsArray) subVars = new VariableCollection(GetArrayElements());
|
||||||
|
// if (IsObject) subVars = this.ObjectSubVariables;
|
||||||
|
// if (IsPrimitive) subVars = new VariableCollection(new Variable[] {});
|
||||||
|
// if (subVars == null) throw new DebuggerException("Unknown value type");
|
||||||
|
// #if DEBUG
|
||||||
|
// return new VariableCollection(subVars.Name,
|
||||||
|
// subVars.Value,
|
||||||
|
// Util.MergeLists(this.GetDebugInfo(), subVars.SubCollections).ToArray(),
|
||||||
|
// subVars.Items);
|
||||||
|
// #else
|
||||||
|
// return subVars;
|
||||||
|
// #endif
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,124 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2022 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
public partial class Value |
||||||
|
{ |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
internal VariableCollection GetDebugInfo() |
||||||
|
{ |
||||||
|
return GetDebugInfo(this.RawCorValue); |
||||||
|
} |
||||||
|
|
||||||
|
internal 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); |
||||||
|
} |
||||||
|
*/ |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,130 @@ |
|||||||
|
// <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 |
||||||
|
{ |
||||||
|
// This part of the class provides support for classes and structures
|
||||||
|
public partial class Value |
||||||
|
{ |
||||||
|
internal ICorDebugObjectValue CorObjectValue { |
||||||
|
get { |
||||||
|
if (IsObject) { |
||||||
|
return CorValue.CastTo<ICorDebugObjectValue>(); |
||||||
|
} else { |
||||||
|
throw new DebuggerException("Value is not an object"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns true if the value is a class or value type </summary>
|
||||||
|
public bool IsObject { |
||||||
|
get { |
||||||
|
return !IsNull && (this.Type.IsClass || this.Type.IsValueType); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns a text which is produced by calling object.ToString() </summary>
|
||||||
|
public Value ObjectToString { |
||||||
|
get { |
||||||
|
return Eval.AsyncInvokeMethod( |
||||||
|
MethodInfo.GetFromName(Process, typeof(object), "ToString", 0), |
||||||
|
this, |
||||||
|
null |
||||||
|
).Result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a field or property of an object with a given name.
|
||||||
|
/// </summary>
|
||||||
|
public NamedValue GetMember(string name) |
||||||
|
{ |
||||||
|
return GetMembers()[name]; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get all fields and properties of an object.
|
||||||
|
/// </summary>
|
||||||
|
public NamedValueCollection GetMembers() |
||||||
|
{ |
||||||
|
return GetMembers(null, BindingFlags.All); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get fields and properties of an object which are defined by a given type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"> Limit to type, null for all types </param>
|
||||||
|
/// <param name="bindingFlags"> Get only members with certain flags </param>
|
||||||
|
public NamedValueCollection GetMembers(DebugType type, BindingFlags bindingFlags) |
||||||
|
{ |
||||||
|
if (IsObject) { |
||||||
|
return new NamedValueCollection(GetObjectMembersEnum(type, bindingFlags)); |
||||||
|
} else { |
||||||
|
return NamedValueCollection.Empty; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerable<NamedValue> GetObjectMembersEnum(DebugType type, BindingFlags bindingFlags) |
||||||
|
{ |
||||||
|
DebugType currentType = type ?? this.Type; |
||||||
|
while (currentType != null) { |
||||||
|
foreach(FieldInfo field in currentType.GetFields(bindingFlags)) { |
||||||
|
yield return field.GetValue(this); |
||||||
|
} |
||||||
|
foreach(PropertyInfo property in currentType.GetProperties(bindingFlags)) { |
||||||
|
yield return property.GetValue(this); |
||||||
|
} |
||||||
|
if (type == null) { |
||||||
|
currentType = currentType.BaseType; |
||||||
|
} else { |
||||||
|
yield break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// public VariableCollection ObjectSubVariables {
|
||||||
|
// get {
|
||||||
|
// return new VariableCollection(String.Empty,
|
||||||
|
// String.Empty,
|
||||||
|
// GetSubCollections(this.Type),
|
||||||
|
// GetSubVariables(this.Type, BindingFlags.Public | BindingFlags.Instance));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// IEnumerable<VariableCollection> GetSubCollections(DebugType type)
|
||||||
|
// {
|
||||||
|
// if (type.BaseType != null) {
|
||||||
|
// yield return new VariableCollection("Base class",
|
||||||
|
// "{" + type.BaseType.Name + "}",
|
||||||
|
// GetSubCollections(type.BaseType),
|
||||||
|
// GetSubVariables(type.BaseType, BindingFlags.Public | BindingFlags.Instance));
|
||||||
|
// }
|
||||||
|
// VariableCollection privateStatic = new VariableCollection("Private static members",
|
||||||
|
// String.Empty,
|
||||||
|
// new VariableCollection[0],
|
||||||
|
// GetSubVariables(type, BindingFlags.NonPublic | BindingFlags.Static));
|
||||||
|
// VariableCollection privateInstance = new VariableCollection("Private members",
|
||||||
|
// String.Empty,
|
||||||
|
// privateStatic.IsEmpty ? new VariableCollection[0] : new VariableCollection[] {privateStatic},
|
||||||
|
// GetSubVariables(type, BindingFlags.NonPublic | BindingFlags.Instance));
|
||||||
|
// if (!privateInstance.IsEmpty) {
|
||||||
|
// yield return privateInstance;
|
||||||
|
// }
|
||||||
|
// VariableCollection publicStatic = new VariableCollection("Static members",
|
||||||
|
// String.Empty,
|
||||||
|
// new VariableCollection[0],
|
||||||
|
// GetSubVariables(type, BindingFlags.Public | BindingFlags.Static));
|
||||||
|
// if (!publicStatic.IsEmpty) {
|
||||||
|
// yield return publicStatic;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
// <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.ComponentModel; |
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
// This part of the class provides support for primitive types
|
||||||
|
// eg int, bool, string
|
||||||
|
public partial class Value |
||||||
|
{ |
||||||
|
ICorDebugGenericValue CorGenericValue { |
||||||
|
get { |
||||||
|
if (IsPrimitive) { |
||||||
|
return CorValue.CastTo<ICorDebugGenericValue>(); |
||||||
|
} else { |
||||||
|
throw new DebuggerException("Value is not a primitive type"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the value is an primitive type.
|
||||||
|
/// eg int, bool, string
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPrimitive { |
||||||
|
get { |
||||||
|
return !IsNull && this.Type.IsPrimitive; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether the type is an integer type </summary>
|
||||||
|
public bool IsInteger { |
||||||
|
get { |
||||||
|
return !IsNull && this.Type.IsInteger; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value of a primitive type.
|
||||||
|
///
|
||||||
|
/// If setting of a value fails, NotSupportedException is thrown.
|
||||||
|
/// </summary>
|
||||||
|
public object PrimitiveValue { |
||||||
|
get { |
||||||
|
if (CorType == CorElementType.STRING) { |
||||||
|
return (CorValue.CastTo<ICorDebugStringValue>()).String; |
||||||
|
} else { |
||||||
|
return CorGenericValue.Value; |
||||||
|
} |
||||||
|
} |
||||||
|
set { |
||||||
|
object newValue; |
||||||
|
TypeConverter converter = TypeDescriptor.GetConverter(this.Type.ManagedType); |
||||||
|
try { |
||||||
|
newValue = converter.ConvertFrom(value); |
||||||
|
} catch { |
||||||
|
throw new NotSupportedException("Can not convert " + value.GetType().ToString() + " to " + this.Type.ManagedType.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
if (CorType == CorElementType.STRING) { |
||||||
|
throw new NotSupportedException(); |
||||||
|
} else { |
||||||
|
CorGenericValue.Value = newValue; |
||||||
|
} |
||||||
|
NotifyChange(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,217 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2022 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
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 class holds data necessaty to obtain the value of a given object
|
||||||
|
/// even after continue. It provides functions to examine the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// 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.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// 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)
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public partial class Value: RemotingObjectBase, IExpirable, IMutable |
||||||
|
{ |
||||||
|
Process process; |
||||||
|
|
||||||
|
CorValueGetter corValueGetter; |
||||||
|
|
||||||
|
ICorDebugValue currentCorValue; |
||||||
|
PauseSession currentCorValuePauseSession; |
||||||
|
|
||||||
|
/// <summary> Occurs when the Value can not be used anymore </summary>
|
||||||
|
public event EventHandler Expired; |
||||||
|
|
||||||
|
/// <summary> Occurs when the Value have potentialy changed </summary>
|
||||||
|
public event EventHandler<ProcessEventArgs> Changed; |
||||||
|
|
||||||
|
bool isExpired = false; |
||||||
|
|
||||||
|
/// <summary> The process that owns the value </summary>
|
||||||
|
public Process Process { |
||||||
|
get { |
||||||
|
return process; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns true if the Value have expired
|
||||||
|
/// and can not be used anymore </summary>
|
||||||
|
public bool HasExpired { |
||||||
|
get { |
||||||
|
return isExpired; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal ICorDebugValue CorValue { |
||||||
|
get { |
||||||
|
return DereferenceUnbox(RawCorValue); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal CorElementType CorType { |
||||||
|
get { |
||||||
|
ICorDebugValue corValue = this.CorValue; |
||||||
|
if (corValue == null) { |
||||||
|
return (CorElementType)0; |
||||||
|
} |
||||||
|
return (CorElementType)corValue.Type; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ICorDebugValue RawCorValue { |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal 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, |
||||||
|
IExpirable[] expireDependencies, |
||||||
|
IMutable[] mutateDependencies, |
||||||
|
CorValueGetter corValueGetter) |
||||||
|
{ |
||||||
|
this.process = process; |
||||||
|
|
||||||
|
AddExpireDependency(process); |
||||||
|
foreach(IExpirable exp in expireDependencies) { |
||||||
|
AddExpireDependency(exp); |
||||||
|
} |
||||||
|
|
||||||
|
foreach(IMutable mut in mutateDependencies) { |
||||||
|
AddMutateDependency(mut); |
||||||
|
} |
||||||
|
|
||||||
|
this.corValueGetter = corValueGetter; |
||||||
|
} |
||||||
|
|
||||||
|
void AddExpireDependency(IExpirable dependency) |
||||||
|
{ |
||||||
|
if (dependency.HasExpired) { |
||||||
|
MakeExpired(); |
||||||
|
} else { |
||||||
|
dependency.Expired += delegate { MakeExpired(); }; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void MakeExpired() |
||||||
|
{ |
||||||
|
if (!isExpired) { |
||||||
|
isExpired = true; |
||||||
|
OnExpired(new ValueEventArgs(this)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void AddMutateDependency(IMutable dependency) |
||||||
|
{ |
||||||
|
dependency.Changed += delegate { NotifyChange(); }; |
||||||
|
} |
||||||
|
|
||||||
|
internal void NotifyChange() |
||||||
|
{ |
||||||
|
if (!isExpired) { |
||||||
|
currentCorValue = null; |
||||||
|
currentCorValuePauseSession = null; |
||||||
|
OnChanged(new ValueEventArgs(this)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Is called when the value changes </summary>
|
||||||
|
protected virtual void OnChanged(ProcessEventArgs e) |
||||||
|
{ |
||||||
|
if (Changed != null) { |
||||||
|
Changed(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Is called when the value expires and can not be
|
||||||
|
/// used anymore </summary>
|
||||||
|
protected virtual void OnExpired(EventArgs e) |
||||||
|
{ |
||||||
|
if (Expired != null) { |
||||||
|
Expired(this, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Returns the <see cref="Debugger.DebugType"/> of the value </summary>
|
||||||
|
public DebugType Type { |
||||||
|
get { |
||||||
|
return DebugType.Create(process, RawCorValue.As<ICorDebugValue2>().ExactType); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> Copy the acutal value from some other Value object </summary>
|
||||||
|
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 class CannotGetValueException: DebuggerException |
||||||
|
{ |
||||||
|
public CannotGetValueException(string message):base(message) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,115 +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; |
|
||||||
using System.Collections.Generic; |
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
[Serializable] |
|
||||||
public class VariableCollection: RemotingObjectBase, IEnumerable<Variable> |
|
||||||
{ |
|
||||||
public static VariableCollection Empty = new VariableCollection(new Variable[] {}); |
|
||||||
|
|
||||||
string name; |
|
||||||
string val; |
|
||||||
IEnumerable<VariableCollection> subCollectionsEnum; |
|
||||||
IEnumerable<Variable> collectionEnum; |
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() |
|
||||||
{ |
|
||||||
return GetEnumerator(); |
|
||||||
} |
|
||||||
|
|
||||||
public IEnumerator<Variable> GetEnumerator() |
|
||||||
{ |
|
||||||
return Items.GetEnumerator(); |
|
||||||
} |
|
||||||
|
|
||||||
public string Name { |
|
||||||
get { |
|
||||||
return name; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public string Value { |
|
||||||
get { |
|
||||||
return val; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public IEnumerable<VariableCollection> SubCollections { |
|
||||||
get { |
|
||||||
return subCollectionsEnum; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public IEnumerable<Variable> Items { |
|
||||||
get { |
|
||||||
return collectionEnum; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public bool IsEmpty { |
|
||||||
get { |
|
||||||
return !SubCollections.GetEnumerator().MoveNext() && |
|
||||||
!Items.GetEnumerator().MoveNext(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
internal VariableCollection(IEnumerable<Variable> collectionEnum) |
|
||||||
:this(String.Empty, String.Empty, new VariableCollection[0], collectionEnum) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public VariableCollection(string name, string val):this(name, val, null, null) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public VariableCollection(string name, string val, IEnumerable<VariableCollection> subCollectionsEnum, IEnumerable<Variable> collectionEnum) |
|
||||||
{ |
|
||||||
this.name = name; |
|
||||||
this.val = val; |
|
||||||
if (subCollectionsEnum != null) { |
|
||||||
this.subCollectionsEnum = subCollectionsEnum; |
|
||||||
} else { |
|
||||||
this.subCollectionsEnum = new VariableCollection[0]; |
|
||||||
} |
|
||||||
if (collectionEnum != null) { |
|
||||||
this.collectionEnum = collectionEnum; |
|
||||||
} else { |
|
||||||
this.collectionEnum = new Variable[0]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public virtual Variable this[string variableName] { |
|
||||||
get { |
|
||||||
int index = variableName.IndexOf('.'); |
|
||||||
if (index != -1) { |
|
||||||
string rootVariable = variableName.Substring(0, index); |
|
||||||
string subVariable = variableName.Substring(index + 1); |
|
||||||
return this[rootVariable].ValueProxy.SubVariables[subVariable]; |
|
||||||
} else { |
|
||||||
foreach (Variable v in this) { |
|
||||||
if (v.Name == variableName) return v; |
|
||||||
} |
|
||||||
} |
|
||||||
throw new DebuggerException("Variable \"" + variableName + "\" is not in collection"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public override string ToString() { |
|
||||||
string txt = ""; |
|
||||||
foreach(Variable v in this) { |
|
||||||
txt += v.ToString() + "\n"; |
|
||||||
} |
|
||||||
return txt; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,27 +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; |
|
||||||
|
|
||||||
namespace Debugger |
|
||||||
{ |
|
||||||
public class VariableEventArgs: ProcessEventArgs |
|
||||||
{ |
|
||||||
Variable variable; |
|
||||||
|
|
||||||
public Variable Variable { |
|
||||||
get { |
|
||||||
return variable; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public VariableEventArgs(Variable variable): base(variable.Value.Process) |
|
||||||
{ |
|
||||||
this.variable = variable; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,56 @@ |
|||||||
|
// <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>
|
||||||
|
/// Represents an element of an array
|
||||||
|
/// </summary>
|
||||||
|
public class ArrayElement: NamedValue |
||||||
|
{ |
||||||
|
uint[] indicies; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The indicies of the element; one for each dimension of
|
||||||
|
/// the array.
|
||||||
|
/// </summary>
|
||||||
|
public uint[] Indicies { |
||||||
|
get { |
||||||
|
return indicies; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal ArrayElement(uint[] indicies, |
||||||
|
Process process, |
||||||
|
IExpirable[] expireDependencies, |
||||||
|
IMutable[] mutateDependencies, |
||||||
|
CorValueGetter corValueGetter) |
||||||
|
:base (GetNameFromIndices(indicies), |
||||||
|
process, |
||||||
|
expireDependencies, |
||||||
|
mutateDependencies, |
||||||
|
corValueGetter) |
||||||
|
{ |
||||||
|
this.indicies = indicies; |
||||||
|
} |
||||||
|
|
||||||
|
static string GetNameFromIndices(uint[] indices) |
||||||
|
{ |
||||||
|
string elementName = "["; |
||||||
|
for (int i = 0; i < indices.Length; i++) { |
||||||
|
elementName += indices[i].ToString() + ","; |
||||||
|
} |
||||||
|
elementName = elementName.TrimEnd(new char[] {','}) + "]"; |
||||||
|
return elementName; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
// <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>
|
||||||
|
/// Represents a local variable in a function
|
||||||
|
/// </summary>
|
||||||
|
public class LocalVariable: NamedValue |
||||||
|
{ |
||||||
|
internal LocalVariable(string name, |
||||||
|
Process process, |
||||||
|
IExpirable[] expireDependencies, |
||||||
|
IMutable[] mutateDependencies, |
||||||
|
CorValueGetter corValueGetter) |
||||||
|
:base (name, |
||||||
|
process, |
||||||
|
expireDependencies, |
||||||
|
mutateDependencies, |
||||||
|
corValueGetter) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 2022 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
using Debugger.Wrappers.CorDebug; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents a member of class or value type -
|
||||||
|
/// that is, a field or a property
|
||||||
|
/// </summary>
|
||||||
|
public class MemberValue: NamedValue |
||||||
|
{ |
||||||
|
MemberInfo memberInfo; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an MemberInfo object which can be used to obtain
|
||||||
|
/// metadata information about the member.
|
||||||
|
/// </summary>
|
||||||
|
public MemberInfo MemberInfo { |
||||||
|
get { |
||||||
|
return memberInfo; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal MemberValue(MemberInfo memberInfo, |
||||||
|
Process process, |
||||||
|
IExpirable[] expireDependencies, |
||||||
|
IMutable[] mutateDependencies, |
||||||
|
CorValueGetter corValueGetter) |
||||||
|
:base (memberInfo.Name, |
||||||
|
process, |
||||||
|
expireDependencies, |
||||||
|
mutateDependencies, |
||||||
|
corValueGetter) |
||||||
|
{ |
||||||
|
this.memberInfo = memberInfo; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
// <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>
|
||||||
|
/// Represents an argument of a function. That is, it refers to
|
||||||
|
/// the runtime value of function parameter.
|
||||||
|
/// </summary>
|
||||||
|
public class MethodArgument: NamedValue |
||||||
|
{ |
||||||
|
int index; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The index of the function parameter starting at 0.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The implicit 'this' is excluded.
|
||||||
|
/// </remarks>
|
||||||
|
public int Index { |
||||||
|
get { |
||||||
|
return index; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
internal MethodArgument(string name, |
||||||
|
int index, |
||||||
|
Process process, |
||||||
|
IExpirable[] expireDependencies, |
||||||
|
IMutable[] mutateDependencies, |
||||||
|
CorValueGetter corValueGetter) |
||||||
|
:base (name, |
||||||
|
process, |
||||||
|
expireDependencies, |
||||||
|
mutateDependencies, |
||||||
|
corValueGetter) |
||||||
|
{ |
||||||
|
this.index = index; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
// <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; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
// public class NamedValueCollection: RemotingObjectBase, IEnumerable<NamedValue>
|
||||||
|
// {
|
||||||
|
// public static NamedValueCollection Empty = new NamedValueCollection(new NamedValue[0]);
|
||||||
|
//
|
||||||
|
// string name;
|
||||||
|
// string val;
|
||||||
|
// IEnumerable<NamedValueCollection> subCollectionsEnum;
|
||||||
|
// IEnumerable<NamedValue> collectionEnum;
|
||||||
|
//
|
||||||
|
// IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
// {
|
||||||
|
// return GetEnumerator();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public IEnumerator<NamedValue> GetEnumerator()
|
||||||
|
// {
|
||||||
|
// return Items.GetEnumerator();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public string Name {
|
||||||
|
// get {
|
||||||
|
// return name;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public string Value {
|
||||||
|
// get {
|
||||||
|
// return val;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public IEnumerable<NamedValueCollection> SubCollections {
|
||||||
|
// get {
|
||||||
|
// return subCollectionsEnum;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public IEnumerable<NamedValue> Items {
|
||||||
|
// get {
|
||||||
|
// return collectionEnum;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public bool IsEmpty {
|
||||||
|
// get {
|
||||||
|
// return !SubCollections.GetEnumerator().MoveNext() &&
|
||||||
|
// !Items.GetEnumerator().MoveNext();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// internal NamedValueCollection(IEnumerable<NamedValue> collectionEnum)
|
||||||
|
// :this(String.Empty, String.Empty, new VariableCollection[0], collectionEnum)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public NamedValueCollection(string name, string val):this(name, val, null, null)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public NamedValueCollection(string name, string val, IEnumerable<NamedValueCollection> subCollectionsEnum, IEnumerable<NamedValue> collectionEnum)
|
||||||
|
// {
|
||||||
|
// this.name = name;
|
||||||
|
// this.val = val;
|
||||||
|
// this.subCollectionsEnum = subCollectionsEnum ?? new VariableCollection[0];
|
||||||
|
// this.collectionEnum = collectionEnum ?? new Variable[0];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// public virtual NamedValue this[string variableName] {
|
||||||
|
// get {
|
||||||
|
// int index = variableName.IndexOf('.');
|
||||||
|
// if (index != -1) {
|
||||||
|
// string rootVariable = variableName.Substring(0, index);
|
||||||
|
// string subVariable = variableName.Substring(index + 1);
|
||||||
|
// return this[rootVariable].Value.SubVariables[subVariable];
|
||||||
|
// } else {
|
||||||
|
// foreach (Variable v in this) {
|
||||||
|
// if (v.Name == variableName) return v;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// throw new DebuggerException("Variable \"" + variableName + "\" is not in collection");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public override string ToString()
|
||||||
|
// {
|
||||||
|
// string txt = "";
|
||||||
|
// foreach(Variable v in this) {
|
||||||
|
// txt += v.ToString() + "\n";
|
||||||
|
// }
|
||||||
|
// return txt;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
// <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; |
||||||
|
|
||||||
|
namespace Debugger |
||||||
|
{ |
||||||
|
// public class VariableEventArgs: ProcessEventArgs
|
||||||
|
// {
|
||||||
|
// Variable variable;
|
||||||
|
//
|
||||||
|
// public Variable Variable {
|
||||||
|
// get {
|
||||||
|
// return variable;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public VariableEventArgs(Variable variable): base(variable.Value.Process)
|
||||||
|
// {
|
||||||
|
// this.variable = variable;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||||
|
// <version>$Revision: 1965 $</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
#pragma warning disable 1591
|
||||||
|
|
||||||
|
namespace Debugger.Wrappers.CorDebug |
||||||
|
{ |
||||||
|
using System; |
||||||
|
|
||||||
|
public partial class ICorDebugArrayValue |
||||||
|
{ |
||||||
|
public unsafe uint[] Dimensions { |
||||||
|
get { |
||||||
|
uint[] dimensions = new uint[this.Rank]; |
||||||
|
fixed (void* pDimensions = dimensions) { |
||||||
|
this.GetDimensions((uint)dimensions.Length, new IntPtr(pDimensions)); |
||||||
|
} |
||||||
|
return dimensions; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public unsafe ICorDebugValue GetElement(uint[] indices) |
||||||
|
{ |
||||||
|
fixed (void* pIndices = indices) { |
||||||
|
return this.GetElement((uint)indices.Length, new IntPtr(pIndices)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#pragma warning restore 1591
|
Loading…
Reference in new issue