3

I'm making a managed .NET debugger using MDBG sample.

MDBG sample operates only on top level class of given instance, not searching deep inside class hierarchy. I was able to go through hierarchy and get all available methods. But a problem occurs in such case:

    public abstract class Base{
        public Base() {SomeProp = "Base"}
        public string SomeProp {get;set;}
    }

    public class A : Base{
        public Base() {SomeProp = "A"}
        public new string SomeProp {get;set;}
    }

    public static void Main(){
        var a = new A();
        var castedToBase = (Base)a;
        //castedToBase.SomeProp -- expect result to be "Base" when debugging
    }

The problem is when I'm getting castedToBase as ICorDebugValue and query for it's ICorDebugValue2::GetExactType I get A class instead of Base class. At that point I cannot distinguish any more which method get_SomeProp to invoke. I would expect ICorDebugValue2::GetExactType to take in consideration performed casts and not return always the underlying type.

How can I understand which method I should invoke?

Some code of what I'm doing now is listed below. mdbgValue represents castedToBase object. szTypedef returns "A" instead of expected "Base"

    IMetadataImport importer;
    var classToken = mdbgValue.CorValue.ExactType.Class.Token;

    int size;
    int ptkExtends;
    TypeAttributes pdwTypeDefFlags;
    importer.GetTypeDefProps(classToken,
        null,
        0,
        out size,
        out pdwTypeDefFlags,
        out ptkExtends
        );
    StringBuilder szTypedef = new StringBuilder(size);
    importer.GetTypeDefProps(classToken,
        szTypedef,
        szTypedef.Capacity,
        out size,
        out pdwTypeDefFlags,
        out ptkExtends
        );
3615
  • 3,787
  • 3
  • 20
  • 35
  • 1
    Casting an object to it's base class doesn't change the object, only how it is perceived. I would suggest you need to pass the "perceived" type around along with the value, and use that instead of the actual type for the purpose of finding the correct method. – Brian Reichle Aug 08 '16 at 09:34
  • @BrianReichle Thank you for suggestion! But I don't have "perceived" type, how debugger should know what cast was performed on the object? – 3615 Aug 08 '16 at 09:38
  • Perhaps 'statically determined type' would be a better name than 'perceived' type. You would grab it from wherever you got the value (field type, parameter type, method/property return type, etc ...) – Brian Reichle Aug 08 '16 at 09:49
  • @BrianReichle Do you mean compiler time type? So to get that I should somehow invoke roslyn giving it my runtime known class name, method name and variable name to get static type? – 3615 Aug 08 '16 at 10:14
  • 1
    No, when I say 'statically determined type', I'm talking about the type you get by looking at the code/metadata rather than by running it or examining the current state of execution. So if you get a value from a parameter, the statically determined type is the type of the parameter. If you got it from a property then it's the type of property. – Brian Reichle Aug 08 '16 at 10:22
  • Ok, now It's clearer for me, but yet, I don't understand how to achieve what you have suggested. What I currently do is just entering some string like "castedToBase.SomeProp", split it using dot separator and search for the first part within local variables (I'm ignoring static/global for the moment). If found, then I continue the search for the rest of nameParts inside class hierarchy. So I don't understand how I can find relation between name of a variable or variable itself and from where it came from. Also, if a cast is performed then the statically determined type is cast type itself... – 3615 Aug 08 '16 at 10:58

1 Answers1

3

Casting an object to it's base class doesn't change the type of the object, only how it is perceived. I would suggest you need to pass the "perceived" type around along with the value, and use that instead of the actual type for the purpose of finding the correct method.

The "perceived" type is the statically determined type based on where you got the value from.

  • If you got the value from a parameter using ICorDebugILFrame::GetArgument(), then extract the corresponding argument type from the method signature.
    • If its the first argument and the method signature has the HasThis flag but not the ExplicitThis flag then get the type from the value instead.
  • If you got the value from a local using ICorDebugILFrame::GetLocalVariable() then extract the type from the methods locals signature (the metadata token of the locals signature needs to be extracted from the method header.)
  • If you got the value from running a method with ICorDebugEval (eg. a property getter), then you should use the return type of the method you called (also extracted from the method signature.)
  • If you got the value from a field, then extract the type from the field signature.
  • If you cast a value, then use whatever type you are casting to.
Brian Reichle
  • 2,798
  • 2
  • 30
  • 34
  • Thank you, Brian! Your answers are saving me from drowning in this sea of doubts. I think now I'm starting to get your point, but I'll need some time to try this out and see where I'll get. The only thing that remains unclear on conceptual level is that last paragraph regarding casts. In that case I have no method signature/field signature to parse, so where from I would get that Type I'm casting to? – 3615 Aug 08 '16 at 12:14
  • That was just thrown in on the assumption that at some point you might want to have support for casting when evaluating an expression in the debugger. eg. `((A)castedToBase).SomeProp` ... perhaps it's premature to worry about that just yet :) – Brian Reichle Aug 08 '16 at 12:24
  • Yes, you are right, the case when I enter some expression like you mentioned is defenetely premature to think about! What I was thinking about is some cast in code, not in the debugger expression. It's just like in the question's example: `var castedToBase = (Base)a;` and then I want to simply to evaluate a property in debugger doing `castedToBase.SomeProp`. Currently I'm sticking to evaluation of fields and properties, nothing more advanced... – 3615 Aug 08 '16 at 12:37