.NET Framework Bookmark and Share   
 index > Building Development and Diagnostic Tools for .Net > Tracking what has changed in an object, parameter, etc.?
 

Tracking what has changed in an object, parameter, etc.?

While an app is running, I want to keep track of everywhere that any field of an object has changed.

I want to be able to do this for all objects in a watch list.

The idea is that when a breakpoint is hit, user can see not just the current state of a watched object, but previous states .. and the line of code that caused a particular state change.

(This is the first time I've written a .NET debugger or profiler, so even very basic suggestions to get me going in a good direction would be most useful.)

I am in the planning stages; deciding how to do this. Stumbled on mdbg, which seems to have much of the code I would need.

Seeing that there are hooks on method entry/exit, my first attempt will be to isolate to method level instead of line of code detail.

Second version would find the IL statements that store values, and somehow figure out which field of which object was being changed. Or something like that.

Also, I realize that a change might be made by some method in system or other class library not under my control, so even the second version would need to check any object that was passed into the call, to see if any field changed.

Q 1: Is there a way to trap a change to a field directly?

Q 2: Even if there is an answer to Q#1, I'd like to explore comparing a current version of an object to a cached version, to find any diffs. IDeas or sample code for doing this?

So far my basic notion is to examine each parameter to method, decide if it is an object I care about, get its metadata, and copy the raw bytes of the object's fields. Then after the call, do that again, but this time comparing the current bytes to the copy, to see what changed.

Q 3: I'm worried about objects moving, and how that will complicate comparing fields that are managed pointers. I am aware of the GC API for knowing when a full collection occurs, so I figure what I should do is update any pointers that have moved. Is there sample code for doing so? (I would need to do the update myself, because the data is being held as raw bytes; GC doesn't know it represents a managed pointer.)

Q 4: Or as alternative to Q 3, is there a general way to clone a shallow copy of an object, and then tell CLR to accept that as a managed object? Then GC would keep my pointers updated if it moved the object. The issue here is that I don't want to trigger any construction code that would normally occur when cloning an object: it really needs to be exactly a mirror of the original, even if that violates a class's semantics [e.g. uniqueness of an auto-increment field in a class mimicking a datarow in a database].

Q 5: Or as another alternative, maybe I can re-arrange my data storage so that all the managed pointers are in a known place, and I can tell GC about them. In that case, how do I tell GC this is a list of managed pointers? Actually, I guess if I hold them in a an array of refs to Object, then that would do it, so maybe Q3 & Q4 are non-issues...



Thanks,
Steve
ToolmakerSteve
Hi, Steve, I think the profiling API has the functionality you need, via IL rewriting (i.e., IL instrumentation). As each function gets JITted, you can inspect the IL to see if that function modifies an object of the type you're interested in. (Note that examining parameters of methods is not enough. Objects accessed via static references will not be revealed in the parameter list, and casting to super-types before passing a parameter--e.g., passing a parameter of type "Object"--would also thwart that approach.) If all your instrumentation & logging code remains in managed code, then you don't have to worry about the GC moving objects out from under you. Your instrumented IL will naturally move along with the object without your being aware. If you do need native code to keep track of objects, you can use the profiling API's MovedReferences() callback (among others), to keep track of when and how objects move around. You could also try adding IL that would "pin" objects with the GC, though it's not recommended you do too much of that, as that can lead to a fragmented heap and modify the behavior of the app.

Unfortunately, the process of doing IL rewriting is frought with many perils, and is not well documented. You can start reading up here:
http://blogs.msdn.com/davbr/archive/2007/03/06/creating-an-il-rewriting-profiler.aspx

Thanks,
Dave

All Replies

  • Tuesday, April 14, 2009 4:18 PMDavid BromanMSFT, OwnerUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hi, Steve, I think the profiling API has the functionality you need, via IL rewriting (i.e., IL instrumentation). As each function gets JITted, you can inspect the IL to see if that function modifies an object of the type you're interested in. (Note that examining parameters of methods is not enough. Objects accessed via static references will not be revealed in the parameter list, and casting to super-types before passing a parameter--e.g., passing a parameter of type "Object"--would also thwart that approach.) If all your instrumentation & logging code remains in managed code, then you don't have to worry about the GC moving objects out from under you. Your instrumented IL will naturally move along with the object without your being aware. If you do need native code to keep track of objects, you can use the profiling API's MovedReferences() callback (among others), to keep track of when and how objects move around. You could also try adding IL that would "pin" objects with the GC, though it's not recommended you do too much of that, as that can lead to a fragmented heap and modify the behavior of the app.

    Unfortunately, the process of doing IL rewriting is frought with many perils, and is not well documented. You can start reading up here:
    http://blogs.msdn.com/davbr/archive/2007/03/06/creating-an-il-rewriting-profiler.aspx

    Thanks,
    Dave
  • Tuesday, April 14, 2009 4:53 PMToolmakerSteve Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks David,

    That is what I needed to know. Especially knowing about "MovedReferences()" callback, and your mention of static references.

    Steve
David Broman

You can use google to search for other answers

Custom Search

More Threads

• Files in PCHEALTH folder..
• Finding amount of data downloaded using Network monitor(NetMon)
• Dofuscator Community Edition, C# dll and unmanaged C++
• Just in Time debugger for C# managed code
• Is an assembly the only possible target for an emitted method?
• C# tuple 2.0 - Logic to be rewritten in 1.1 framework
• Enable Process Performance Counters
• Re: Steppers and Exception filters
• Help!My program sometimes can't exit normally
• Unable to to use Managed debugger sample by Mike Stalls