YanGu
YanGu

Reputation: 3032

How to add a BreakPoint in C# code in WinDbg to view the value of local variable?

First of all, is it possible to view local variables in C# code in WinDbg.exe by adding SOS.dll?

I loaded the SOS.dll extension into WinDbg.exe by using .cordll -ve -u -l command. The machine is x86. The result of the command is:

CLRDLL: Loaded DLL C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll
Automatically loaded SOS Extension
CLR DLL status: Loaded DLL C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll

I thought the SOS.dll has been loaded successfully. Then I want to insert a BreakPoint in the code. By testing the F9 seems not work. So I use the !bpmd command to insert a break point, like this:

0:004> !bpmd MyCode.exe Program.Main
PDB symbol for clr.dll not loaded
Found 1 methods in module 00714044...
MethodDesc = 00714d50
Setting breakpoint: bp 00760869 [Demo.Program.Main(System.String[])]
Adding pending breakpoints...
0:004> bl
     1 e Disable Clear  00760869     0001 (0001)  0:**** 

But the result is:

0:004> g
eax=00000024 ebx=00000001 ecx=00eff73c edx=77592740 esi=00000000 edi=77621a20
eip=77592740 esp=00eff73c ebp=00eff750 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!KiFastSystemCallRet:
77592740 c3   

Why the breakpoint is not hit?

Hope anyone could give me some help!

Upvotes: 1

Views: 1233

Answers (1)

Thomas Weller
Thomas Weller

Reputation: 59208

You didn't post the full debug session, but let me draw a few conclusions:

  1. you are on thread 4, which means you are already beyond the initial breakpoint. (Otherwise there would be only thread 0)
  2. !bpmd worked immediately, which means the Main method was already jitted.
  3. Since the Main method was already jitted, it is already run.
  4. Since the Main method is already run, there is no reason to break there again (except the very unlikely case you call it recursively)

MRE

In the following example, I am using this program:

class Program
{
    static void Main()
    {
        int x = 5;
        var p = new Program();
        var i = x;
        Console.WriteLine("Debug now.");
        Console.ReadLine();
        // Ensure variables are needed
        Console.WriteLine(x+i+p.ToString()); 
    }
}

Please provide such an example yourself next time, so we don't need to come up with an example ourselves.

I compile it in Release mode, AnyCPU with 32 bit preferred.

I am debugging with WinDbg Preview 1.2103.01004.0

How to break on Program.Main()?

Launch the application in WinDbg, so that it will stop at the initial breakpoint like this:

ntdll!LdrpDoDebuggerBreak+0x2b:
77ee1a62 cc              int     3
0:000> 

We need .NET SOS, so

0:000> sxe ld clrjit
0:000> *** Wait until .NET is loaded
0:000> g

And some time later, .NET is available

ModLoad: 72180000 7220a000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
[...]
ntdll!NtMapViewOfSection+0xc:
77ea2c0c c22800          ret     28h
0:000>

Get yourself a copy of the SOSEX extension and load it. It simplifies things.

0:000> .load D:\debug\ext\sosex\x86\sosex.dll
0:000> 

Set a breakpoint at Program.Main:

0:000> !mbm *!*Program.Main
0:000> !mbl
2 e : disable *!*PROGRAM.MAIN ILOffset=0: pass=1 oneshot=false thread=ANY
    SO67212401!SO67212401.Program.Main(string[]) (PENDING JIT)

Note the "pending JIT", which means Main() has not been run yet. Let's wait for it:

0:000> g
ModLoad: 77b10000 77ba6000   C:\WINDOWS\SysWOW64\OLEAUT32.dll
Breakpoint: JIT notification received for method SO67212401.Program.Main(System.String[]) in AppDomain 01090fe8.
Breakpoint set at SO67212401.Program.Main(System.String[]) in AppDomain 01090fe8.
Breakpoint 2 hit

We are in Main()!

0:000> !clrstack
OS Thread Id: 0x5614 (0)
Child SP       IP Call Site
00efed3c 01560853 SO67212401.Program.Main(System.String[]) [C:\...\SO67212401\Program.cs @ 9]
00efeebc 7529f036 [GCFrame: 00efeebc] 

How to see local variables?

If you step throught the code with !mt and !mgu, you'll reach the second Console.WriteLine() call:

0:000> !clrstack
OS Thread Id: 0x5614 (0)
Child SP       IP Call Site
00efed38 736d4f64 System.Console.WriteLine(System.String)
00efed3c 015608a3 SO67212401.Program.Main(System.String[]) [C:\...\Program.cs @ 16]
00efeebc 7529f036 [GCFrame: 00efeebc] 

Have a look at local variables and parameters using !clrstack -l -p:

0:000> !clrstack -l -p
OS Thread Id: 0x5614 (0)
Child SP       IP Call Site
00efed38 736d4f64 System.Console.WriteLine(System.String)
    PARAMETERS:
        value (<CLR reg>) = 0x0309522c

00efed3c 015608a3 SO67212401.Program.Main(System.String[]) [C:\...\Program.cs @ 16]
    PARAMETERS:
        args = <no data>
    LOCALS:
        <no data>
        <no data>
        0x00efed3c = 0x0000000a

00efeebc 7529f036 [GCFrame: 00efeebc] 

So: there is only 1 local variable with a value of 10. And the parameter is

0:000> !do 0309522c
Name:        System.String
[...]
String:      10SO67212401.Program              <-- string value
Fields:
[...]

a concatenated string made of "10" and the name of the object.

Try this in debug mode and you'll see non-optimized version of variables.

Upvotes: 1

Related Questions