Debugging NetCF applications with CorDbg - Part VI: Function evaluation

Previous debugger series entries: I, II, III, IV, V

This week's installment of the debugging NetCF applicaitons using CorDbg series covers function evaluation (funceval).

Commands referenced
f[unceval] Function evaluation
newo[bj] Create a new object via function evaluation
news[tr] Create a new string via function evaluation
sh[ow] Display source code lines
w[here] Display a stack trace for the current thread

Modes referenced
ShowTypeArgs Type arguments to generic methods will not be shown in stack trace
ShowModules Module names will not be shown in stack trace

For those who aren't familiar with it, function evaluation allows you to experiment with method calls while debugging. Typically, this doesn't impact the running of your application. I say "typically" because if the method you call during a funceval changes class/application global/instance data, the running of your application can be altered.

Static methods
Evaluating static methods is, by far, the easiest form of function evaluation. All you need to do is call the method with your desired arguments. The funceval, shown below, takes two arguments (both integers) and reports back which is largest.

(cordbg) f NetCF.Test.TestDebuggee::PrivateStaticMethod 55 34
Function evaluation complete.
$result=(strong handle, Size: 4) (0x0004c78c) "arg1"

The only part that may get tricky is getting CorDbg to find the function... If you have been reading the previous parts of this series, you may remember that I recommend keeping the your debugger modes set as shown below.
ShowArgs=1
ShowModules=1

ShowModules and ShowArgs are really quite helpful here. If you are having a hard time getting CorDbg to evaluate your method, use the stack to help you.

My first attempt at producing the above example hit a snag:
(cordbg) f TestDebuggee::PrivateStaticMethod 54 33
Could not find function: TestDebuggee::PrivateStaticMethod

Since I had ShowModules enabled, I was able to see the fully qualifies class name and successfully evaluate the method:
(cordbg) w
Thread 0x716f537a Current State:Normal
0)* NetCF.Test.TestDebuggee::Main +0000[IL] in <path>\TestDebuggee.cs:32

(cordbg) f NetCF.Test.TestDebuggee::PrivateStaticMethod 55 34
Function evaluation complete.
$result=(strong handle, Size: 4) (0x0004c78c) "arg1"

Instance methods
Evaluating instance methods is a little trickier, but not by much. If you have ever done COM programming in C, this will seem natural to you.  Function evaluation on instance methods require an additional argument to the call. You need to provide the debugger with the object from which you want to invoke the method (pran is the variable that contains the object instance). 

(cordbg) f SomeOtherNamespace.PrivateClassInAnotherNamespace::ReturnMagicNumber pran 45
Function evaluation complete.
$result=1169951822

Of course, since you must have an instance of an object to pass. There are two ways to get an instance of your target object... First, you can execute enough of your application for the object to have been created (as shown above) -- watch out for methods that update object instance state.

The second option (the one I personally like best) is to have the debugger instantiate an instance of your target object on your behalf.
(cordbg) newo SomeOtherNamespace.InternalClassInAnotherNamespace
Function evaluation complete.
$result=(strong handle, Size: 4) (0x0010058c) <SomeOtherNamespace.InternalClassInAnotherNamespace>

Once complete, $result will contain an instance of your target object. You can then evaluate your target method, without need to run more of your application than you wish to and without fear of tampering with the state of your applications instance of the object.

(cordbg) f SomeOtherNamespace.InternalClassInAnotherNamespace::ReturnMagicNumber $result 6
Function evaluation complete.
$result=3

You'll notice that $result gets overwritten whenever a function evaluation occurs. If you write down the hex value displayed when the newo[bj] command returns (0x0010058c, in my example), you can use that in future f[unceval] calls.

(cordbg) f SomeOtherNamespace.InternalClassInAnotherNamespace::ReturnMagicNumber 0x0010058c 12
Function evaluation complete.
$result=0

(cordbg) f SomeOtherNamespace.InternalClassInAnotherNamespace::ReturnMagicNumber 0x0010058c 14
Function evaluation complete.
$result=2

One other note, funceval can only accept variables, addresses and integers as arguments. If you need to pass a string to a method, you will need to use the new[str] command (also places the object instance in $result). You can then call methods which take strings.
(cordbg) newstr Someone
Function evaluation complete.
$result=(strong handle, Size: 4) (0x0010043c) "Someone"

(cordbg) f NetCF.Test.TestDebuggee::PublicInstanceMethod app $result 75
Function evaluation complete.
$result=(strong handle, Size: 4) (0x00100a94) "Hey, everyone! Someone is 75 years old!"

Pretty neat, isn't it? Well, that's all for today,
-- DK

Disclaimers:
This posting is provided "AS IS" with no warranties, and confers no rights.
Some of the information contained within this post may be in relation to beta software. Any and all details are subject to change.

[2004-07-23: Edited to clarify newstr example]