|
|
|
@ -18,54 +18,24 @@ namespace Debugger
@@ -18,54 +18,24 @@ namespace Debugger
|
|
|
|
|
{ |
|
|
|
|
public class ObjectValue: Value |
|
|
|
|
{ |
|
|
|
|
ICorDebugClass corClass; |
|
|
|
|
ICorDebugModule corModule; |
|
|
|
|
MetaData metaData; |
|
|
|
|
ICorDebugModule corModuleSuperclass; |
|
|
|
|
ObjectValue baseClass; |
|
|
|
|
Module finalCorClassModule; |
|
|
|
|
uint finalCorClassToken; |
|
|
|
|
|
|
|
|
|
Module module; |
|
|
|
|
ICorDebugClass corClass; |
|
|
|
|
TypeDefProps classProps; |
|
|
|
|
|
|
|
|
|
public override string AsString { |
|
|
|
|
get { |
|
|
|
|
return "{" + Type + "}"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public ObjectValue BaseClassObject { |
|
|
|
|
protected ICorDebugObjectValue CorObjectValue { |
|
|
|
|
get { |
|
|
|
|
ObjectValue baseClass = this; |
|
|
|
|
while (baseClass.HasBaseClass) { |
|
|
|
|
baseClass = baseClass.BaseClass; |
|
|
|
|
} |
|
|
|
|
return baseClass; |
|
|
|
|
return this.CorValue.CastTo<ICorDebugObjectValue>(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
IEnumerable<MethodProps> Methods { |
|
|
|
|
get { |
|
|
|
|
return this.Module.MetaData.EnumMethods(this.ClassToken); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
// May return null
|
|
|
|
|
public Eval ToStringEval { |
|
|
|
|
public override string AsString { |
|
|
|
|
get { |
|
|
|
|
ObjectValue baseClassObject = this.BaseClassObject; |
|
|
|
|
foreach(MethodProps method in baseClassObject.Methods) { |
|
|
|
|
if (method.Name == "ToString") { |
|
|
|
|
ICorDebugValue[] evalArgs; |
|
|
|
|
ICorDebugFunction evalCorFunction; |
|
|
|
|
baseClassObject.Module.CorModule.GetFunctionFromToken(method.Token, out evalCorFunction); |
|
|
|
|
evalArgs = new ICorDebugValue[] {this.SoftReference}; |
|
|
|
|
return new Eval(debugger, evalCorFunction, evalArgs); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
throw new DebuggerException("ToString method not found"); |
|
|
|
|
return "{" + Type + "}"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
public override string Type { |
|
|
|
|
get{ |
|
|
|
@ -75,7 +45,7 @@ namespace Debugger
@@ -75,7 +45,7 @@ namespace Debugger
|
|
|
|
|
|
|
|
|
|
public Module Module { |
|
|
|
|
get { |
|
|
|
|
return debugger.GetModule(corModule); |
|
|
|
|
return module; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -85,24 +55,63 @@ namespace Debugger
@@ -85,24 +55,63 @@ namespace Debugger
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal unsafe ObjectValue(NDebugger debugger, PersistentValue pValue):base(debugger, pValue) |
|
|
|
|
public ObjectValue BaseClass { |
|
|
|
|
get { |
|
|
|
|
ICorDebugClass superClass = GetSuperClass(debugger, corClass); |
|
|
|
|
if (superClass == null) throw new DebuggerException("Does not have a base class"); |
|
|
|
|
return new ObjectValue(debugger, pValue, superClass); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool HasBaseClass { |
|
|
|
|
get { |
|
|
|
|
return GetSuperClass(debugger, corClass) != null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal ObjectValue(NDebugger debugger, PersistentValue pValue):base(debugger, pValue) |
|
|
|
|
{ |
|
|
|
|
corClass = this.CorValue.CastTo<ICorDebugObjectValue>().Class; |
|
|
|
|
InitObjectVariable(); |
|
|
|
|
InitObjectValue(this.CorObjectValue.Class); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal unsafe ObjectValue(NDebugger debugger, PersistentValue pValue, ICorDebugClass corClass):base(debugger, pValue) |
|
|
|
|
internal ObjectValue(NDebugger debugger, PersistentValue pValue, ICorDebugClass corClass):base(debugger, pValue) |
|
|
|
|
{ |
|
|
|
|
this.corClass = corClass; |
|
|
|
|
InitObjectVariable(); |
|
|
|
|
InitObjectValue(corClass); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void InitObjectVariable () |
|
|
|
|
void InitObjectValue(ICorDebugClass corClass) |
|
|
|
|
{ |
|
|
|
|
corModule = corClass.Module; |
|
|
|
|
metaData = Module.MetaData; |
|
|
|
|
classProps = metaData.GetTypeDefProps(corClass.Token); |
|
|
|
|
corModuleSuperclass = corModule; |
|
|
|
|
this.finalCorClassModule = debugger.GetModule(this.CorObjectValue.Class.Module); |
|
|
|
|
this.finalCorClassToken = this.CorObjectValue.Class.Token; |
|
|
|
|
|
|
|
|
|
this.module = debugger.GetModule(corClass.Module); |
|
|
|
|
this.corClass = corClass; |
|
|
|
|
this.classProps = Module.MetaData.GetTypeDefProps(corClass.Token); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool IsCorValueCompatible { |
|
|
|
|
get { |
|
|
|
|
ObjectValue freshValue = this.FreshValue as ObjectValue; |
|
|
|
|
return freshValue != null && |
|
|
|
|
this.finalCorClassModule == freshValue.Module && |
|
|
|
|
this.finalCorClassToken == freshValue.ClassToken; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public ObjectValue ObjectClass { |
|
|
|
|
get { |
|
|
|
|
ObjectValue objectClass = this; |
|
|
|
|
while (objectClass.HasBaseClass) { |
|
|
|
|
objectClass = objectClass.BaseClass; |
|
|
|
|
} |
|
|
|
|
return objectClass; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
IEnumerable<MethodProps> Methods { |
|
|
|
|
get { |
|
|
|
|
return this.Module.MetaData.EnumMethods(this.ClassToken); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override bool MayHaveSubVariables { |
|
|
|
@ -111,24 +120,24 @@ namespace Debugger
@@ -111,24 +120,24 @@ namespace Debugger
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override IEnumerable<Variable> GetSubVariables(PersistentValue pValue) |
|
|
|
|
public override IEnumerable<Variable> GetSubVariables() |
|
|
|
|
{ |
|
|
|
|
if (HasBaseClass) { |
|
|
|
|
yield return GetBaseClassVariable(pValue); |
|
|
|
|
yield return GetBaseClassVariable(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
foreach(Variable var in GetFieldVariables(pValue)) { |
|
|
|
|
foreach(Variable var in GetFieldVariables()) { |
|
|
|
|
yield return var; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
foreach(Variable var in GetPropertyVariables(pValue)) { |
|
|
|
|
foreach(Variable var in GetPropertyVariables()) { |
|
|
|
|
yield return var; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public IEnumerable<Variable> GetFieldVariables(PersistentValue pValue) |
|
|
|
|
public IEnumerable<Variable> GetFieldVariables() |
|
|
|
|
{ |
|
|
|
|
foreach(FieldProps f in metaData.EnumFields(ClassToken)) { |
|
|
|
|
foreach(FieldProps f in Module.MetaData.EnumFields(ClassToken)) { |
|
|
|
|
FieldProps field = f; // One per scope/delegate
|
|
|
|
|
if (field.IsStatic && field.IsLiteral) continue; // Skip field
|
|
|
|
|
if (!field.IsStatic && CorValue == null) continue; // Skip field
|
|
|
|
@ -136,19 +145,32 @@ namespace Debugger
@@ -136,19 +145,32 @@ namespace Debugger
|
|
|
|
|
field.Name, |
|
|
|
|
field.IsStatic, |
|
|
|
|
field.IsPublic, |
|
|
|
|
new PersistentValue(debugger, delegate { return GetCorValueOfField(field, pValue); })); |
|
|
|
|
new PersistentValue(debugger, delegate { return GetCorValueOfField(field); })); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ICorDebugValue GetCorValueOfField(FieldProps field, PersistentValue pValue) |
|
|
|
|
ICorDebugValue GetCorValueOfField(FieldProps field) |
|
|
|
|
{ |
|
|
|
|
Value updatedVal = pValue.Value; |
|
|
|
|
if (updatedVal is UnavailableValue) throw new CannotGetValueException(updatedVal.AsString); |
|
|
|
|
if (!this.IsEquivalentValue(updatedVal)) throw new CannotGetValueException("Object type changed"); |
|
|
|
|
return GetCorValue(updatedVal, 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 (debugger.IsPaused && debugger.SelectedThread != null && debugger.SelectedThread.LastFunction != null && debugger.SelectedThread.LastFunction.CorILFrame != null) { |
|
|
|
|
curFrame = debugger.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(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public IEnumerable<Variable> GetPropertyVariables(PersistentValue pValue) |
|
|
|
|
public IEnumerable<Variable> GetPropertyVariables() |
|
|
|
|
{ |
|
|
|
|
foreach(MethodProps m in Methods) { |
|
|
|
|
MethodProps method = m; // One per scope/delegate
|
|
|
|
@ -157,149 +179,101 @@ namespace Debugger
@@ -157,149 +179,101 @@ namespace Debugger
|
|
|
|
|
method.Name.Remove(0, 4), |
|
|
|
|
method.IsStatic, |
|
|
|
|
method.IsPublic, |
|
|
|
|
delegate { return CreatePropertyEval(method, pValue); }); |
|
|
|
|
delegate { return CreatePropertyEval(method); }); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Eval CreatePropertyEval(MethodProps method, PersistentValue pValue) |
|
|
|
|
Eval CreatePropertyEval(MethodProps method) |
|
|
|
|
{ |
|
|
|
|
Value updatedVal = pValue.Value; |
|
|
|
|
if (updatedVal is UnavailableValue) { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
if (this.IsEquivalentValue(updatedVal)) { |
|
|
|
|
ICorDebugFunction evalCorFunction = Module.CorModule.GetFunctionFromToken(method.Token); |
|
|
|
|
|
|
|
|
|
return new Eval(debugger, evalCorFunction, delegate { return GetArgsForEval(method, pValue); }); |
|
|
|
|
} else { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ICorDebugValue[] GetArgsForEval(MethodProps method, PersistentValue pValue) |
|
|
|
|
{ |
|
|
|
|
ObjectValue updatedVal = pValue.Value as ObjectValue; |
|
|
|
|
if (this.IsEquivalentValue(updatedVal)) { |
|
|
|
|
if (method.IsStatic) { |
|
|
|
|
return new ICorDebugValue[] {}; |
|
|
|
|
} else { |
|
|
|
|
if (updatedVal.SoftReference != null) { |
|
|
|
|
return new ICorDebugValue[] {updatedVal.SoftReference.CastTo<ICorDebugValue>()}; |
|
|
|
|
} else { |
|
|
|
|
return new ICorDebugValue[] {updatedVal.CorValue}; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override bool IsEquivalentValue(Value val) |
|
|
|
|
{ |
|
|
|
|
ObjectValue objVal = val as ObjectValue; |
|
|
|
|
return objVal != null && |
|
|
|
|
objVal.ClassToken == this.ClassToken; |
|
|
|
|
if (!IsCorValueCompatible) return null; |
|
|
|
|
|
|
|
|
|
ICorDebugFunction evalCorFunction = Module.CorModule.GetFunctionFromToken(method.Token); |
|
|
|
|
return new Eval(debugger, evalCorFunction, delegate { return GetArgsForEval(method); }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ICorDebugValue GetCorValue(Value val, FieldProps field) |
|
|
|
|
ICorDebugValue[] GetArgsForEval(MethodProps method) |
|
|
|
|
{ |
|
|
|
|
// Current frame is used to resolve context specific static values (eg. ThreadStatic)
|
|
|
|
|
ICorDebugFrame curFrame = null; |
|
|
|
|
if (debugger.IsPaused && debugger.SelectedThread != null && debugger.SelectedThread.LastFunction != null && debugger.SelectedThread.LastFunction.CorILFrame != null) { |
|
|
|
|
curFrame = debugger.SelectedThread.LastFunction.CorILFrame.CastTo<ICorDebugFrame>(); |
|
|
|
|
} |
|
|
|
|
if (!IsCorValueCompatible) return null; |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
if (field.IsStatic) { |
|
|
|
|
return corClass.GetStaticFieldValue(field.Token, curFrame); |
|
|
|
|
if (method.IsStatic) { |
|
|
|
|
return new ICorDebugValue[] {}; |
|
|
|
|
} else { |
|
|
|
|
if (this.SoftReference != null) { |
|
|
|
|
return new ICorDebugValue[] {this.SoftReference.CastTo<ICorDebugValue>()}; |
|
|
|
|
} else { |
|
|
|
|
return (val.CorValue.CastTo<ICorDebugObjectValue>()).GetFieldValue(corClass, field.Token); |
|
|
|
|
return new ICorDebugValue[] {this.CorValue}; |
|
|
|
|
} |
|
|
|
|
} catch { |
|
|
|
|
throw new CannotGetValueException(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Variable GetBaseClassVariable(PersistentValue pValue) |
|
|
|
|
public Variable GetBaseClassVariable() |
|
|
|
|
{ |
|
|
|
|
if (HasBaseClass) { |
|
|
|
|
return new Variable(debugger, |
|
|
|
|
"<Base class>", |
|
|
|
|
new PersistentValue(delegate { return GetBaseClassValue(pValue); })); |
|
|
|
|
new PersistentValue(debugger, delegate { return GetBaseClassValue(); })); |
|
|
|
|
} else { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Value GetBaseClassValue(PersistentValue pValue) |
|
|
|
|
Value GetBaseClassValue() |
|
|
|
|
{ |
|
|
|
|
Value updatedVal = pValue.Value; |
|
|
|
|
if (updatedVal is UnavailableValue) return updatedVal; |
|
|
|
|
if (this.IsEquivalentValue(updatedVal)) { |
|
|
|
|
return ((ObjectValue)updatedVal).BaseClass; |
|
|
|
|
} else { |
|
|
|
|
return new UnavailableValue(debugger, "Object type changed"); |
|
|
|
|
} |
|
|
|
|
if (!IsCorValueCompatible) return new UnavailableValue(debugger, "Object type changed"); |
|
|
|
|
|
|
|
|
|
return this.BaseClass; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public unsafe ObjectValue BaseClass { |
|
|
|
|
get { |
|
|
|
|
if (baseClass == null) baseClass = GetBaseClass(); |
|
|
|
|
if (baseClass == null) throw new DebuggerException("Object doesn't have a base class. You may use HasBaseClass to check this."); |
|
|
|
|
return baseClass; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool HasBaseClass { |
|
|
|
|
get { |
|
|
|
|
if (baseClass == null) { |
|
|
|
|
try { |
|
|
|
|
baseClass = GetBaseClass(); |
|
|
|
|
} catch (DebuggerException) { |
|
|
|
|
baseClass = null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return (baseClass != null); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected ObjectValue GetBaseClass() |
|
|
|
|
protected static ICorDebugClass GetSuperClass(NDebugger debugger, ICorDebugClass currClass) |
|
|
|
|
{ |
|
|
|
|
string fullTypeName = "<>"; |
|
|
|
|
|
|
|
|
|
// If referencing to external assembly
|
|
|
|
|
if ((classProps.SuperClassToken & 0x01000000) != 0) { |
|
|
|
|
|
|
|
|
|
fullTypeName = metaData.GetTypeRefProps(classProps.SuperClassToken).Name; |
|
|
|
|
|
|
|
|
|
classProps.SuperClassToken = 0; |
|
|
|
|
foreach (Module m in debugger.Modules) |
|
|
|
|
{ |
|
|
|
|
Module currModule = debugger.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 debugger.Modules) { |
|
|
|
|
// TODO: Does not work for nested
|
|
|
|
|
// see FindTypeDefByName in dshell.cpp
|
|
|
|
|
// TODO: preservesig
|
|
|
|
|
try { |
|
|
|
|
classProps.SuperClassToken = m.MetaData.FindTypeDefByName(fullTypeName, 0).Token; |
|
|
|
|
uint token = superModule.MetaData.FindTypeDefByName(fullTypeName, 0).Token; |
|
|
|
|
return superModule.CorModule.GetClassFromToken(token); |
|
|
|
|
} catch { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
corModuleSuperclass = m.CorModule; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If it has no base class
|
|
|
|
|
if ((classProps.SuperClassToken & 0x00FFFFFF) == 0) { |
|
|
|
|
throw new DebuggerException("Unable to get base class: " + fullTypeName); |
|
|
|
|
} else { |
|
|
|
|
ICorDebugClass superClass = corModuleSuperclass.GetClassFromToken(classProps.SuperClassToken); |
|
|
|
|
if (corHandleValue != null) { |
|
|
|
|
return new ObjectValue(debugger, new PersistentValue(debugger, corHandleValue.As<ICorDebugValue>()), superClass); |
|
|
|
|
} else { |
|
|
|
|
return new ObjectValue(debugger, new PersistentValue(debugger, CorValue), superClass); |
|
|
|
|
|
|
|
|
|
throw new DebuggerException("Superclass not found"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
// May return null
|
|
|
|
|
public Eval ToStringEval { |
|
|
|
|
get { |
|
|
|
|
ObjectValue baseClassObject = this.BaseClassObject; |
|
|
|
|
foreach(MethodProps method in baseClassObject.Methods) { |
|
|
|
|
if (method.Name == "ToString") { |
|
|
|
|
ICorDebugValue[] evalArgs; |
|
|
|
|
ICorDebugFunction evalCorFunction; |
|
|
|
|
baseClassObject.Module.CorModule.GetFunctionFromToken(method.Token, out evalCorFunction); |
|
|
|
|
evalArgs = new ICorDebugValue[] {this.SoftReference}; |
|
|
|
|
return new Eval(debugger, evalCorFunction, evalArgs); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
throw new DebuggerException("ToString method not found"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|