In Part I of NetCF debugging with cordbg, I showed you how to get the debugger connected to your process. In this part, I'm going to talk a little about cordbg's mode command.
But before we get to that, I had a question from a reader as to why the "launch me debuggable" command line argument (//i) starts with "//" instead of the more traditional "/" (or "-"). Over the course of it's development, NetCF has had a number of execution engine options exposed on the command line, all using the "//" semantic. We chose this format because we felt is was highly unlikely that an actual application would have an argument that started with "//". This was chosen back when all we had was a command line interface in NetCF (that was a very long time ago) and has stuck. While we could have switched over to using the device's registry, the lack of a registry editor on our target platforms made for a difficult user experience, so the command line options remained.
Back to the topic at hand... As you saw in part I, the first thing you did after starting cordbg was to issue the "mode embeddedclr 1" command. What this did was to instruct the debugger to use the NetCF provided implementation of the managed debugger interfaces. Without this step (which you only need to do once, unless you toggle it back to 0), cordbg uses the .NET Framework's implementation of these interfaces and cannot debug your process.
But this is not the only cool thing that the mode command can do for you. If you type "? mode" at the (cordbg) prompt, you will see something resembling the following.
AppDomainLoads=1 AppDomain and Assembly load events are not displayedClassLoads=1 Class load events are not displayedDumpMemoryInBytes=0 Memory is dumped in DWORDSEnhancedDiag=0 Suppress display of diagnostic informationHexDisplay=1 Numbers are displayed in hexadecimalILNatPrint=0 Offsets will be IL xor native-relativeISAll=0 All interceptors are skippedISClinit=0 Class initializers are skippedISExceptF=0 Exception filters are skippedISInt=0 User interceptors are skippedISPolicy=0 Context policies are skippedISSec=0 Security interceptors are skippedJitOptimizations=0 JIT's will produce debuggable (non-optimized) codeLoggingMessages=0 Managed log messages are suppressedModuleLoads=1 Module load events are displayedSeparateConsole=0 Debuggees share cordbg's consoleShowArgs=1 Arguments will be shown in stack traceShowModules=1 Module names will be included in stack traceShowStaticsOnPrint=0 Static fields are not included when displaying objectsShowSuperClassOnPrint=0 Super class names are not included when displaying objectsUnmanagedTrace=0 Unmanaged debug events are not displayedUSAll=0 Unmapped stop locations are skippedUSEpi=0 Epilogs are skipped, returning to calling methodUSPro=0 Prologs are skippedUSUnmanaged=0 Unmanaged code is skippedWin32Debugger=0 CorDbg is not the Win32 debugger for all processesEmbeddedCLR=1 Embedded CLR applications are debugged
These are the settings that I use when I am debugging (this display is from my home machine, in fact). We'll talk a little more about most of these a little later. But first...
As with most things in NetCF, we have factored the functionality of the debugger interfaces. Of the cordbg modes shown in the listing above, the following are not supported when debugging device projects.
ISAll Step through all interceptorsISInt Step through user interceptorsISPolicy Step through context policiesISSec Step through security interceptorsJitOptimizations JIT compilation generates debuggable codeLoggingMessages Display managed code log messagesUnmanagedTrace Display unmanaged debug eventsUSAll Step through all unmapped stop locationsUSEpi Step through method epilogsUSPro Step through method prologsUSUnmanaged Step through unmanaged codeWin32Debugger Specify Win32 debugger (UNSUPPORTED: use at your own risk)
And now... "My Favorite Modes".
AppDomainLoadsIf your application starts a new appdomain or loads assemblies, this mode will help you to keep track of exactly when these events are occuring. They also help you to see if there are any loads you were not expecting -- perhaps a 3rd party assembly you are using is loading something large.
ClassLoadsThis tells the debugger to display a message whenever a new class is loaded. Again, helpful to see exactly what is going on in your code.
HexDisplayMaybe this is due to my early days working on Win95 (we used wdeb386 then). I got accustomed to seeing values as hex and found it was nice when looking at flags values.
ModuleLoadsSimilar to AppDomainLoads and ClassLoads, this lets you see what your application is loading into memory.
ShowArgsShowModulesThese give you much more complete data when looking at stack traces. ShowArgs provides you with argument names. ShowModules adds module names. ShowModules is particularly helpful when figuring out how to set breakpoints (cordbg can be a bit touchy wrt breakpoint formatting -- this will be covered in a future part of this series).
EmbeddedCLROf course, without this, debugging NetCF applications would not be possible.
How about a few examples? I have been working on a simple triva game off|on for quite awhile. The examples below are from a basic debugging session using this applicaiton as the debuggee.
For space reasons, I will not show an example of AppDomainLoads, ClassLoads or HexDisplay. AppDomainLoads and ClassLoads are similar to what you get with ModuleLoads. HexDisplay is pretty obvious.
With ModuleLoads enabled, the results of the connect command look something like this:Process 1934213950/0x7349c33e created.Warning: couldn't load symbols for <path>\mscorlib.dllModule 0x002683f4, <path>\mscorlib.dll-- Loaded in assembly 0x0026830c, mscorlib.dll in appdomain #463396, TrivialThings.exeModule 0x00a35e84, <path>\TrivialThings.exe -- Loaded in assembly 0x00a34634, \Program Files\TrivialThings\TrivialThings.exe in appdomain #463396, TrivialThings.exeWarning: couldn't load symbols for <path>\System.Drawing.dllModule 0x00a34dd4, <path>\System.Drawing.dll -- Loaded in assembly 0x00a38fd4, System.Drawing.dll in appdomain #463396, TrivialThings.exeWarning: couldn't load symbols for <path>\System.dllModule 0x00a49e2c, <path>\System.dll -- Loaded in assembly 0x0026cb54, System.dll in appdomain #463396, TrivialThings.exeWarning: couldn't load symbols for <path>\System.Windows.Forms.dllModule 0x00a3554c, <path>\System.Windows.Forms.dll -- Loaded in assembly 0x0026cb94, System.Windows.Forms.dll in appdomain #463396, TrivialThings.exe[thread 0x71784] Thread created.
As you can see from the example, ModuleLoads not only tells you what was loaded but which assembly was loaded into what appdomain.
When you set ShowArgs and ShowModules, your stack traces (where command) become very nice.
Thread 0x71784 Current State:Normal0)* TrivialThings!TrivialThings.GameEngine::.ctor +0000[IL] in <path>\GameEngine.cs:33 board=(0x00097360) <TrivialThings.RectangularGameBoard> die=(0x002e1b80) <TrivialThings.Die> serverAddress=<null>1) TrivialThings!TrivialThings.MainForm::.ctor +00a9[IL] in <path>\mainform.cs:712) TrivialThings!TrivialThings.MainForm::Main +000a[IL] in <path>\mainform.cs:141
I, for one, find it very useful to see the names of the arguments (sometimes I have a hard time keeping track of which argument does what) and besides, .NET assemblies are self describing, so why not take advantage of it.
Also, as mentioned above, sometimes it's hard to figure out just what format cordbg wants for breakpoints. Here's how ShowModules helps you here (you can just copy from the stack, and modify as needed).
Well, that's all for this part... Stay tuned for future installments, including (in no particular order):* Breakpoints and stepping* Working with source* Stack walking* Threads and exceptions* IL debugging* Cordbg and NetCF v2
Until next time.-- DK
Disclaimer:This posting is provided "AS IS" with no warranties, and confers no rights.