Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to view c# variables using windbg

I have a C# windows service installed on a 32 bit windows server 2003 machine that I wish to debug.

The problem I have is that a log file error message tells me the following:

System.NullReferenceException: Object reference not set to an instance of an object.
at VideoProcessor.ResetCameraProperties(DataServiceObject dso)
at VideoProcessor.AddServer(DataServiceObject dso)
at VideoProcessor.LoadServers()
at VideoProcessor.Start()
atVideoServerComponent.Connect()

The actual code for the function ResetCameraProperties is:

protected void ResetCameraProperties(DataServiceObject dso)
    {
        // Find the CameraType.
        //Type videoCameraType = TypeManager.Instance["XFire.Common.VideoObjects.VideoServer"];
        if (_videoCameraType == null) return;

        //Load cameras from the Data Service Layer
        string whereClause = "ServerID = ?";
        object[] args = new object[] { dso["ObjectID"] };
        IDataServiceCollection videoCameraDsoCollection = ClientServerConnection.Instance.FindCollection(_videoCameraType, whereClause, args, null, CollectionOptions.FilterByPartitionResponsibility) as IDataServiceCollection;
        if (videoCameraDsoCollection == null || 0 == videoCameraDsoCollection.Count)
            return;
        videoCameraDsoCollection.LoadContainerOnEnumeration = false;

        foreach (DataServiceObject camera in videoCameraDsoCollection)
        {
            if (!(bool)dso[RecorderKey.Online] && (int)dso[RecorderKey.VideoServerAlarm] == (int)VideoServerComponent.GetVideoServerAlarm("Offline"))
            {
                // If the server is disconnected, then we know everything should be offline.
                camera[CameraKey.VideoCameraAlarm] = VideoServerComponent.GetEnumValueOfType("XFire.Common.VideoObjectDefinitions.VideoCameraAlarm", "Unknown");
                camera[CameraKey.Videoloss] = true;
            }
            else if ((bool)dso[RecorderKey.Online] && (int)dso[RecorderKey.VideoServerAlarm] == (int)VideoServerComponent.GetVideoServerAlarm("Online"))
            {
                camera[CameraKey.VideoCameraAlarm] = VideoServerComponent.GetEnumValueOfType("XFire.Common.VideoObjectDefinitions.VideoCameraAlarm", "Normal");
                camera[CameraKey.Videoloss] = false;
            }

            // Save the camera.
            ServerResult result = ClientServerConnection.Instance.PersistObject(camera, null);
            if (result.Fault != null)
            {
                if (VideoTrace.TraceError) Trace.WriteLine(result.Fault.Message);
            }
     }          
  1. I have opened windbg and did File-->Attach to process

  2. I have set breakpoints in the function above using the steps outlined here: https://learn.microsoft.com/en-us/archive/blogs/alejacma/managed-debugging-with-windbg-preparing-the-environment

  3. When the breakpoint is hit I step forward using F10 but all I see is the following:

    Setting breakpoint: bp 05A0A260 [VideoProcessor.*ResetCameraProperties (XFire.Common.DataServiceLayer.DataServiceObject)] Adding pending breakpoints... 0:024> g DriverWindowsService.OnStop Service stopping... Breakpoint 0 hit eax=00000001 ebx=00902870 ecx=00a1e020 edx=01066e78 esi=00affb48 edi=01066e78 eip=05a0a260 esp=0674e68c ebp=0674e6b0 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 05a0a260 55 push ebp 0:024> p eax=00000001 ebx=00902870 ecx=00a1e020 edx=01066e78 esi=00affb48 edi=01066e78 eip=05a0a261 esp=0674e688 ebp=0674e6b0 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 05a0a261 8bec mov ebp,esp 0:024> p eax=00000001 ebx=00902870 ecx=00a1e020 edx=01066e78 esi=00affb48 edi=01066e78 eip=05a0a263 esp=0674e688 ebp=0674e688 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 05a0a263 57 push edi

This means nothign to me at present (I'm a windbg newbie)

  1. I have the pdb file for the windows service (I got from the Visual Studio Debug Output folder) and have copied itto my target machine in a folder C:\Symbols.

  2. In winDbg I did File-->Symbol FIle path and set it to the location of this pdb file I copied over. My symbol path is as follows: C:\symcache;C:\Symbols;srvc:\symcachehttp://msdl.microsoft.com/download/symbols

  3. In Windbg I did View-->Watch and I typed in the name of a variable that is inside the function above (videoCameraType). But I got the following error:




    *** Either you specified an unqualified symbol, or your debugger *** *** doesn't have full symbol information. Unqualified symbol *** *** resolution is turned off by default. Please either specify a *** *** fully qualified symbol module!symbolname, or enable resolution *** *** of unqualified symbols by typing ".symopt- 100". Note that *** *** enabling unqualified symbol resolution with network symbol *** *** server shares in the symbol path may cause the debugger to *** *** appear to hang for long periods of time when an incorrect *** *** symbol name is typed or the network symbol server is down. ***


    *** For some commands to work properly, your symbol path *** *** must point to .pdb files that have full type information. ***


    *** Certain .pdb files (such as the public OS symbols) do not *** *** contain the required information. Contact the group that *** *** provided you with these symbols if you need this command to *** *** work. ***


    *** Type referenced: _videoCameraType ***



How can I view variables and generally see what is going on in my code???? I also have the source code for the windows service if thats any help.

Thanks

like image 740
Harry Boy Avatar asked Dec 12 '22 13:12

Harry Boy


2 Answers

First thing is that your symbol files are probably not matching binaries as there is no source file paths and line numbers in your exception stack trace. You mentioned that you copied them from the Visual Studio Debug Output, so I assume that you have binaries compiled in Release (with no symbols) and pdb files from Debug. This won't work. What you need to do is change the project settings for your service, recompile and deploy it (you should now have pdb, dll and exe files in the release output folder). This should generate a much more meaningful stack trace for your exception.

Now, the second part. You need to distinguish a managed environment from the native one. In windbg you are debugging the CLR as it is seen by the operating system, thus you are debugging not only your C# application but the CLR interpreter that compiles your ILASM (compiled C# code) to native CPU instructions and then executes them. So you are a layer below what you normally see in VS (with managed debugger attached). Keeping that in mind you need to either dig into CLR internals and try to figure out what the addresses in registers mean or use some sort of translator which will do this heavy work for you. And this is where SOS comes into play. You've already used it when you set the breakpoint. As you are only interested in knowing a value of your variable you need to first find out at what address the CLR lied it out for you. From what I see the _videoCameraType is a private class member, isn't it? If so you may dump managed objects from the stack using !dso command. You should see something similar to the output below:

> !dso
OS Thread Id: 0xad8 (0)
RSP/REG          Object           Name
000000000068E8F0 00000000025f2bc8 Program+Test
000000000068E8F8 00000000025f2be0 System.String    test
000000000068E910 00000000025f2bc8 Program+Test
000000000068E918 00000000025f2bc8 Program+Test

where Program+Test would be replaced by your class name. Then you may dump the object content using !do command and the address from the Object column:

> !do 00000000025f2bc8 
Name:        Program+Test
MethodTable: 000007fe58333a08
EEClass:     000007fe584422b8
Size:        24(0x18) bytes
File:        D:\temp\Test.exe
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feb4dcb318  4000001        8        System.String  0 instance 00000000025f2be0 _testVariable

Find the class member by its name and use !do command once again but using address from the Value column (this works for reference types). In our example it would be:

0:000> !do 00000000025f2be0 
Name:        System.String
MethodTable: 000007feb4dcb318
EEClass:     000007feb4733720
Size:        34(0x22) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:      test
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feb4dce0c8  40000aa        8         System.Int32  1 instance                4 m_stringLength
000007feb4dcc600  40000ab        c          System.Char  1 instance               74 m_firstChar
000007feb4dcb318  40000ac       18        System.String  0   shared           static Empty
                                 >> Domain:Value  000000000074f960:NotInit  <<

Things get trickier if you need to figure out what a value of a local variable is. You may try with !CLRStack -a which usually does not show much in release builds. You are then left with analysis of the generated assembly (!U @rip) in order to find out where the address of your variables landed (registry, stack). After figuring this out, issue again the !do command with the address you've found. Happy debugging :)

like image 94
Sebastian Avatar answered Dec 19 '22 15:12

Sebastian


Adding to this thread since it shows up in Google searches:

The following worked for me:

(If application uses .net 4 use .loadby sos clr to load the SOS debugger extension)

Once you are on the right thread first use !clrstack -p to dump the stack along with the addresses of the local variables.

Now use the address of the local variable of interest to dump it using !do .

Then using the addresses from the output that you get - you can use !do again (use the Value field here for the address of a specific member). You can continue till you are able to see the value you desire.

(You can also use this approach to dump members of the "this" pointer which you obtain from the stack. This may have some variables of interest based on what you are looking for)

See http://blogs.msdn.com/b/alejacma/archive/2009/08/11/managed-debugging-with-windbg-thread-stacks-part-1.aspx

Debugging is exciting! Have fun with it!

like image 41
shivesh suman Avatar answered Dec 19 '22 14:12

shivesh suman