setting managed breakpoints in windbg
Windbg is a native debugger and you can use it to set a breakpoint on a virtual address. Any managed code running within the process wouldn’t have a virtual address associated with it until it is JIT compiled. Thus setting a breakpoint on a managed function is a bit tricky in Windbg. You can set a breakpoint on managed methods using windbg only:
- When you are performing a live debug & not on a post mortem dump file.
- You have a .RUN file from a Time Travel Debug trace.
When I started learning how to set managed breakpoints, one of the first questions I had is: How to set a breakpoint on a specific line of code in a managed method – because that is what we usually do in other IDE environments like Visual Studio. This is somewhat very difficult to do because, though you can get the virtual address where your method starts using the SOS commands, you will need to know the exact offset from the method’s starting virtual address [The actual address which corresponds to your line of code] and it isn’t easy at all to co-relate that to your source code. You will need to have an extremely good understanding of IL code, un-assemble the function using !u command and then set the breakpoint on that address. I do not have that skill yet, but will surely put out a post once I figure that out. So over here, I will describe how to set a breakpoint on a managed method for .NET Framework 2.0.
STEP 1: So assuming you are doing a live debug, the first step is to attach to the process that you want to debug. You can use the attach option in Windbg user interface [File menu]. Then load the SOS debugger extension - !loadby SOS mscorwks
STEP 2: You need to know which method you want to set a breakpoint on. The SOS command you need is !dumpmt with the –md parameter. This lists out the method table. For example, Dump the method table of System.Timespan
1: !dumpmt -md 0x7911228c
2: EEClass: 791121e4
3: Module: 790c2000
4: Name: System.TimeSpan
5: mdToken: 02000114 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
6: BaseSize: 0x10
7: ComponentSize: 0x0
8: Number of IFaces in IFaceMap: 3
9: Slots in VTable: 56
10: --------------------------------------
11: MethodDesc Table
12: Entry MethodDesc JIT Name
13: 796d2710 7914fb28 NONE System.TimeSpan.ToString()
14: 793624d0 7914b950 PreJIT System.Object.Finalize()
15: 796c07f8 7914fb08 NONE System.TimeSpan.CompareTo(System.TimeSpan)
16: 796d2708 7914fb18 NONE System.TimeSpan.Equals(System.TimeSpan)
17: 79381054 79266eb8 PreJIT System.TimeSpan..ctor(Int64)
18: 7939f058 79266ec0 PreJIT System.TimeSpan..ctor(Int32, Int32, Int32)
19: 7939f07c 79266ed8 PreJIT System.TimeSpan.get_Ticks()
20: 794002c8 79266ee0 PreJIT System.TimeSpan.get_Days()
21: 794002e8 79266ee8 PreJIT System.TimeSpan.get_Hours()
22: 79400328 79266ef0 PreJIT System.TimeSpan.get_Milliseconds()
23: 7940036c 79266ef8 PreJIT System.TimeSpan.get_Minutes()
24: 794003ac 79266f00 PreJIT System.TimeSpan.get_Seconds()
25: 794003ec 79266f08 PreJIT System.TimeSpan.get_TotalDays()
26: 7940040c 79266f10 PreJIT System.TimeSpan.get_TotalHours()
27: 79380c10 79266f18 PreJIT System.TimeSpan.get_TotalMilliseconds()
28:
STEP 3: [Optional] Using the method descriptor command, !dumpmd you can view if the code is JITted. See line #7 below. You can skip this and go to STEP 4 directly using the corresponding MethodDesc value from the previous output.
1: !dumpmd 79266f18
2: Method Name: System.TimeSpan.get_TotalMilliseconds()
3: Class: 791121e4
4: MethodTable: 7911228c
5: mdToken: 0600101e
6: Module: 790c2000
7: IsJitted: yes
8: m_CodeOrIL: 79380c10
STEP 4: Add the breakpoint using !bpmd –md command.
1: !bpmd –md 79380c10
Another way…
Syntax: !bpmd <ModuleName> <FunctionName>
Example: !bpmd mscorlib.dll System.TimeSpan.get_TotalMilliseconds
Notes
- The method names are case sensitive.
- In many cases, the breakpoints you set may be indicated as “Pending breakpoints”, which is normal, because your method may not yet be JITted.
Once your breakpoints are set, you can execute the g command to let the process execute till it hits the breakpoint. Once it hits the breakpoint you can do other tasks like examine callstacks, stack objects, local variables etc.
Have fun!