Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / CLR / June 2006

Tip: Looking for answers? Try searching our database.

How to get current running values from .LocalVariables in .NET 2.0?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Lou Zher - 05 Jun 2006 16:52 GMT
We've got a project that needs to be able to see the current running values
from the objects returned back by .LocalVariables. How is this done?
LocalVariables only appears to give us the types of the method vars.
-LZ
Mattias Sjögren - 05 Jun 2006 19:02 GMT
>How is this done?

It can't be done with Reflection.

Mattias

Signature

Mattias Sjögren [C# MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

Lou Zher - 07 Jun 2006 15:29 GMT
Mattias,
Hmm... I was afraid of that. Well, at least I know to bag looking for a
solution inside there. Is there something else I should be looking at? I've
looked briefly at the Debugging API, but it seems horribly complicated to
use for this purpose -- and I'm unclear as to how to make the connection
between the references I find via reflection to values I would obtain via
ICorDebug and friends -- or should I discover the stack/heap from the
debugging API, skipping Reflection altogether?
-LZ

>>How is this done?
>
> It can't be done with Reflection.
>
> Mattias
Ben Voigt - 06 Jun 2006 13:53 GMT
> We've got a project that needs to be able to see the current running
> values from the objects returned back by .LocalVariables. How is this
> done? LocalVariables only appears to give us the types of the method vars.
> -LZ

What are you trying to do?  The values of local variables in any method are
only well-defined at very specific times.

If you are trying to add additional information to an exception stack trace,
please realize that by the time control reaches a handler, the call stack is
already unwound, and stack space may have been overwritten by, for example,
finally blocks that have already executed.

Only methods still on the call stack have valid locals.

If you are in the Exception constructor trying to capture the information,
then it is theoretically possible to capture the details, however consider
that the MSIL is converted to machine code, so any solution is going to be
architecture and runtime specific.  For example, mono might store local
variables in a different order than ms.net.  There's a WinAPI routine
StackWalk that might be of some use... but not much.  You basically require
the debugging API distributed with the JIT compiler, since only it can
determine where the variables are stored.

Also remember that in the case of recursion, there may be multiple stack
frames corresponding to a single MethodBody and LocalVariableInfo.

If you're wanting an automated way to enumerate local variables in the
current method, please consider that your code will never be reuseable
because the process of encapsulating it changes the scope of variable
capture.

The runtime provides minidump functionality, I suggest you use that in lieu
of any attempt to capture state information on your own.
Lou Zher - 06 Jun 2006 17:31 GMT
> What are you trying to do?  The values of local variables in any method
> are only well-defined at very specific times.
Ben...  In a word, Yes. I'm trying to get a stack trace goodies.

> If you are trying to add additional information to an exception stack
> trace, please realize that by the time control reaches a handler, the call
> stack is already unwound, and stack space may have been overwritten by,
> for example, finally blocks that have already executed.
> Only methods still on the call stack have valid locals.

Well, that's true, but there is a workaround. Exception handling involves a
two phase stack walk. The first walks up the stack to look for a qualifying
catcher of the exception thrown. Using exception filtering via the WHEN
clause in VB.NET, one can generate StackTrace info while the throwing code
is still alive. It has to be since the second unwind hasn't occurred yet,
which is where the finally blocks are executed. Only then would the locals
of each method be allowed to go out of scope. Here's some interesting code
to try out:

Sub Main()
   Try
       Helper()
   Catch ex As Exception When ExceptionFilter()
   End Try
End Sub

Sub Helper()
   MakeExceptionHappen()
End Sub

Sub MakeExceptionHappen()
   Throw New ApplicationException("Bummer")
End Sub

Function ExceptionFilter() as Boolean
   Dim st as New StackTrace()    'gets a stack trace at this point
   Console.WriteLine(st.ToString)
   Return False
End Function

'and what is printed is:
'  at blah.blah.ExceptionFilter(Exception ex)
'  at blah.blah.Main()   <-- This is interesting!
'  at blah.blah.MakeExceptionHappen()
'  at blah.blah.Helper()
'  at blah.blah.Main()
'  at System.AppDomain.nExecuteAssembly ....yadda.yadda......

So what appears to be happening is that the first phase of the exception
handling is walking up the stack looking for a qualifying exception handler
and then injecting a 'call' to a fragment inside Main which in turn calls
the ExceptionFilter. This means that everything down to the point of the
thrower is still available just as though the thrower had called the
ExceptionFIlter code itself.

Okay, so forget about all that stuff for a moment because it's not really
relevant. The question remains, can I get the current values of vars still
in scope via Reflection, Introspection, Debugging API, whatever... I'd like
to get statics, object instance vars, method parameters, and method locals.

Thanks for your help so far Ben.
-LZ
Ben Voigt - 07 Jun 2006 18:25 GMT
>> What are you trying to do?  The values of local variables in any method
>> are only well-defined at very specific times.
[quoted text clipped - 14 lines]
> would the locals of each method be allowed to go out of scope. Here's some
> interesting code to try out:

I didn't realize VB.NET gave you access to exception filters... my mistake.
Do you get any exception information (which points to the stack frame where
the exception occurred, since as you noticed the filter is layered on top of
the excepting method) in the exception filter?

For the level of detail you are desiring, you should consider a minidump
file.  I think this note in MiniDumpWriteDump is especially important:
MiniDumpWriteDump may not produce a valid stack trace for the calling
thread. To work around this problem, you must capture the state of the
calling thread before calling MiniDumpWriteDump and use it as the
ExceptionParam parameter. One way to do this is to force an exception inside
a __try/__except block and use the EXCEPTION_POINTERS information provided
by GetExceptionInformation

Since you already have an exception, that should not be a problem, although
getting the exception information in the correct format could be.

> Sub Main()
>    Try
[quoted text clipped - 37 lines]
> like to get statics, object instance vars, method parameters, and method
> locals.

I don't think you will have any luck using the Debugging API within your
managed application to attach to itself.

> Thanks for your help so far Ben.
> -LZ
Lou Zher - 07 Jun 2006 19:17 GMT
> I didn't realize VB.NET gave you access to exception filters... my
> mistake. Do you get any exception information (which points to the stack
> frame where the exception occurred, since as you noticed the filter is
> layered on top of the excepting method) in the exception filter?

Yeah, isn't that cool? And yes, you can get exception information. In my
example, ex is accessible to the filter. So I can generate a StackTrace
based on the exception, which would exclude the filter calls, or I can just
gen a new one based on the current context. This is really neat because it
also means I can examine and exception and choose to catch it or not, vs.
catching it, examining it and choosing to rethrow it or not.

You can also add a filter operand to a .try descriptor in MSIL.

> For the level of detail you are desiring, you should consider a minidump
> file.  I think this note in MiniDumpWriteDump is especially important:
[quoted text clipped - 12 lines]
> I don't think you will have any luck using the Debugging API within your
> managed application to attach to itself.

Hmmm... that seems interesting. I will look into MiniDumpWriteDump more, but
it seems like that is totally outside the managed space.

My understanding of the Debugging API (which is very poor) was that you'd
want to have unmanaged code running in a different thread calling that, but
have it triggerable from the managed code so you can capture context.

A related problem was that I'd like to be able to apply this type of
technique to the SetEnterLeaveFunctionHooks from the Profiling API to be
able to watch state as methods are executed. Anyone have any experience with
this?

This doesn't seem like it should be so dang hard. Does anyone know what
Visual Studio or mdbg uses to see running values in the locals and autos
debugging windows? (I know, I could just download mdbg source and RTFS but
I'm hoping someone here has already done that.)

BTW: I have the Debugging Applications for Microsoft .NET and Microsoft
Windows by John Robbins (http://www.amazon.com/gp/product/0735615365) . An
excellent book, but it falls a little short of helping me with this project.
I've tried some of the goodies that are on the CD that comes with the book
with mixed results. I anxiously await the release of his new book for .NET
2.0 (http://www.amazon.com/gp/product/0735622027). I mention these in case
anyone has had better fortune than I in getting some of the Debugging API
and Profiling API programs working so I can ask, how useful are these? Is it
worth the effort to get these running?

Ben, Thanks again for your help.
-LZ
Lou Zher - 09 Jun 2006 15:14 GMT
After some more messing around with this idea, I have come to the
realization that I cannot get the running values from .LocalVariables or
.ParameterInfo directly, but I'm not giving up yet. It seems Reflection is
only designed to operate with a static vision of assemblies, not running
ones.

Here's the list of tactics I am looking into:
* still looking into what I can do using ICorDebug
* looking at the mdbg source to see how I can replicate its ability to see
these vars. I stepped through its execution of the 'Print' command, but I
must admit to be a bit perplexed as to where the real magic happens.
* looking at some form of code injection to automate a series of calls to
publicize these scoped vars to a publicly accessible thingy

Is anyone here experienced in doing any of these? Can you offer any
tips/tricks regarding these techniques? Are there other techniques I may be
missing? I looked at MiniDump, per Ben's suggestion, but it doesn't appear
to offer any way to connect its contents with the variable names/types I can
get.

Is there another group that is more appropriate for these types of
questions? Is there a web forum that is worth trying?

I appreciate your help.
-LZ
Ben Voigt - 09 Jun 2006 16:38 GMT
> After some more messing around with this idea, I have come to the
> realization that I cannot get the running values from .LocalVariables or
[quoted text clipped - 15 lines]
> appear to offer any way to connect its contents with the variable
> names/types I can get.

The minidump file is the Windows analogue to a core file.  It can be opened
with your normal debugger, and you'll be able to see stack trace, local
variables, static variables, threads, walk through the trees of contained
objects, etc.  In addition, you keep your .pdb files in your development
environment.

Under most circumstances, the fact that your users can't connect the
contents of a minidump file with the variable names is "A Good Thing".

> Is there another group that is more appropriate for these types of
> questions? Is there a web forum that is worth trying?
>
> I appreciate your help.
> -LZ
Lou Zher - 09 Jun 2006 23:01 GMT
Ben,
I am now playing around with mdbgcore.dll and have pretty good success with
it. Using Mike Stall's example sure helped.

http://blogs.msdn.com/jmstall/archive/2005/11/28/snapshot.aspx

Because this operates as a debugger, the stack capture code has to live in a
different process, which isn't quite what I wanted, but I'm making it work.
I'm just using System.Diagnostics.Debugger.Break() in the exception filter
to signal into the debugger and have it stack dump.

Works quite nicely. Yay!
-LZ

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.