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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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