Initializing the CLR Environment and the First JITted Method
The normal action of a Windows program would now be to call the loaded DLLs' entry-points in an order determined by the operating system and then your main executable's entry-point, e.g., mainCRTStartup. But the activity of LdrpCorReplaceStartContext has altered the normal course of events -- press F5 and the debugger will now stop Wilderland.EXE in MSCOREE.DLL!__CorExeMain. If you have the debug symbols for MSCOREE loaded, you should see the following instruction somewhere in the listing:
0x7917D099: CALL long __stdcall GetInstallation(int,struct HINSTANCE__ * *,int); (0x79178DC5) [for SP2:] 0x788110AE: CALL 0x78803216
Step over this call and refresh the Index. Wow! The Index has gained a large number of new nodes! More memory has been allocated and new DLLs have been loaded. A little further along you will find a call through the contents of EAX; run to this now. The popup bubble is displaying what appears to be a substantial amount of code. Double-clicking on the line opens up a new disassembly window for MSCORWKS.DLL!__CorExeMain -- this is the entry-point for the main engine of the Common Language Runtime or CLR. If you are interested in how the .NET environment is loaded and initialized, step through this code! There is a lot of activity going on! In fact, make a mental note of the appearance of the Index now, step over the call to this CorExeMain and refresh the Index. WOW!!! The Wilderland.EXE process has grown quite a bit. There also now appears another disassembly window, this one containing the code for the managed routine, System.AppDomain::SetupDomain. A few more View menu commands have been enabled as well, e.g., View/JIT Events. Try this command now. Now we see the results of selecting the option from the CLR Debug tab sheet, "Break on first JIT event?" There is only one JIT event displayed. With this window activated, select Edit/MSIL Disassemble and a new window is created, the Intermediate Language (IL) display for the method, System.AppDomain::SetupDomain. Single-step through the x86 code and observe what is going on in the IL disassembly window. You will see the current IL instruction pointer jumping and advancing as well. If this display is a little confusing, we can fix that. Close the IL window and in the Index find and select the node for MSCORLIB.DLL (This action will load the .NET symbols.). Now, go back to x86 disassembly window and toggle the Edit menu command, Include MSIL. (You may need to toggle the command twice -- one of the quirks in PEBrowse Interactive's interface.) You should now see the IL disassembly marbled through the x86 instructions that were generated by the JIT compiler.
While we are sitting in the first managed breakpoint, let's add a few more breakpoints to the list. Find the Wilderland.EXE node in the Index and expand it. You will see two nodes with very similar text, ".NET MetaData" and ".NET Methods". Expanding the former will display all of the metadata grouped by major categories, e.g., TypeDefs, ModuleRefs, AssemblyRefs, etc., while the latter, only the .NET methods themselves. Expand the ".NET Methods" node followed by the "Wilderland.WilderlandForm" node. Using the popup menu, set breakpoints on the "Main" node and the "Hobbiton_Button_Click" nodes and bring up the breakpoints display to check your effort. You should now be viewing two pending breakpoints that have been marked "Not JITted" in the bottom half of the display. Press F5 to continue the program. The contents of the disassembly window will now be replaced by the JITted code for the Wilderland.WilderlandForm::Main method, the first instruction of the sample program. Finally! Since we wish to celebrate the appearance of our first bit of code and having so much fun adding managed breakpoints, let us add one more after a point where the System.Windows.Forms.Application::Run method will return:
; IL_0005: call System.Windows.Forms.Application::Run() 0x6E51117: MOV ECX,0x6ED7BFC 0x6E5111C: CALL class Object * __fastcall JIT_NewCrossContext(struct CORINFO_CLASS_STRUCT_ *) ; (0x791B2303) 0x6E51121: MOV ESI,EAX 0x6E51123: MOV ECX,ESI 0x6E51125: CALL DWORD PTR [0x6ED8198] 0x6E5112B: MOV ECX,ESI 0x6E5112D: CALL DWORD PTR [0x6ED8794] ; IL_000A: ldc.i4.0 ; IL_000B: newobj System.IntPtr::.ctor() ; IL_0010: ldstr "The adventure is ending." ; IL_0015: ldstr "Farewell" ; IL_001A: ldc.i4.0 ; IL_001B: call Wilderland.WilderlandForm::MessageBox() ; IL_0020: pop 0x6E51133: LEA ECX,DWORD PTR [EBP-0x4] ; VAR:0x4 <<<<<<<<<< Add a breakpoint here. 0x6E51136: XOR EDX,EDX 0x6E51138: CALL DWORD PTR [0x6E6294C] 0x6E5113E: PUSH DWORD PTR [0x5B710B0] 0x6E51144: PUSH 0x0 0x6E51146: MOV EDX,DWORD PTR [0x5B710AC] 0x6E5114C: MOV ECX,DWORD PTR [EBP-0x4] ; VAR:0x4 0x6E5114F: CALL DWORD PTR [0x6ED8194] ; IL_0021: ret 0x6E51155: NOP
One more View menu item will become enabled here -- View/.NET GC Heap; select it and you will be presented with a dialog box (see Figure 9).
Figure 9
You may notice that a value has already been entered in the edit field; this represents the results of a heuristic inside of PEBrowse Interactive to locate the start of the .NET small object garbage-collected heap. It may be incorrect, and you are given a chance to override it. The Index display based on this algorithm also labels nodes with the text, ".NET GC Heap (Small Object)" and ".NET GC Heap (Large Object)". Press "OK" if you are satisfied with the guess, after a short pause you will open a new window for the .NET GC heap. (This operation and the following might be unavailable if you are using v2.0 of the framework. There is a lot of sanity checking in PEBrowse Interactive's heuristic that can cause it to fail in searching for the GC heap starting address.) For the moment try to resist the temptation to start expanding and exploring the nodes in the tree view display (it will figure prominently a little later in this tutorial). Instead, try to remember that this is a snapshot of the small object heap at this point in the program's execution and that you will need to refresh it (or close and reopen it again) in order to gain an accurate picture of the managed objects. You also might want to revisit the JIT events display to learn more about the activity that takes place before your program is even started. Let the program continue.
| | 1st page | next page |