如何使用windbg查看c#变量

Posted

技术标签:

【中文标题】如何使用windbg查看c#变量【英文标题】:How to view c# variables using windbg 【发布时间】:2013-07-17 14:31:31 【问题描述】:

我在一台 32 位 windows server 2003 机器上安装了一个 C# windows 服务,我想调试它。

我遇到的问题是日志文件错误消息告诉我以下内容:

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()

函数ResetCameraProperties的实际代码是:

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);
            
               

    我打开了windbg并做了File-->Attach to process

    我已使用此处概述的步骤在上述函数中设置断点:https://docs.microsoft.com/en-us/archive/blogs/alejacma/managed-debugging-with-windbg-preparing-the-environment

    当断点被击中时,我使用 F10 向前走,但我看到的只是以下内容:

    设置断点:bp 05A0A260 [VideoProcessor.*ResetCameraProperties (XFire.Common.DataServiceLayer.DataServiceObject)] 添加挂起的断点... 0:024> 克 DriverWindowsService.OnStop 服务停止... 断点 0 命中 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 推送 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 推送编辑

目前这对我来说没什么意义(我是一个windbg新手)

    我有 Windows 服务的 pdb 文件(我从 Visual Studio 调试输出文件夹中获得)并将其复制到我的目标计算机的文件夹 C:\Symbols 中。

    在 winDbg 中,我做了 File-->Symbol FIle path 并将其设置为我复制过来的这个 pdb 文件的位置。我的符号路径如下: C:\symcache;C:\Symbols;srvc:\symcachehttp://msdl.microsoft.com/download/symbols

    在 Windbg 中,我执行了 View-->Watch 并输入了上述函数内部的变量名称 (videoCameraType)。但我收到以下错误:




    *** 您指定了一个不合格的符号,或者您的调试器 *** *** 没有完整的符号信息。不合格符号*** *** 分辨率默认关闭。请指定一个*** *** 完全限定符号模块!符号名,或启用解析 *** 通过键入“.symopt- 100” *** 不合格符号。注意 *** *** 使用网络符号启用不合格的符号解析 *** *** 符号路径中的服务器共享可能会导致调试器 *** *** 出现错误时会长时间挂起 *** *** 输入符号名称或网络符号服务器已关闭。 ***


    *** 要使某些命令正常工作,您的符号路径 *** *** 必须指向具有完整类型信息的 .pdb 文件。 ***


    *** 某些 .pdb 文件(例如公共 OS 符号)不会 *** *** 包含所需的信息。联系该组*** *** 如果您需要此命令,则为您提供这些符号 *** *** 工作。 ***


    *** 引用的类型:_videoCameraType ***



如何查看变量并大致了解我的代码中发生了什么???? 如果有帮助,我也有 Windows 服务的源代码。

谢谢

【问题讨论】:

对这篇文章的几个建议,1) 你能在这个问题中添加 C# 标签吗? 2)你能修复你的代码缩进吗? 3)错字:这对我来说意味着nothign 【参考方案1】:

首先,您的符号文件可能与二进制文件不匹配,因为您的异常堆栈跟踪中没有源文件路径和行号。您提到您从 Visual Studio 调试输出中复制了它们,所以我假设您在 Release 中编译了二进制文件(没有符号)和来自 Debug 的 pdb 文件。这行不通。你需要做的是change the project settings for your service,重新编译并部署它(你现在应该在发布输出文件夹中有pdb、dll和exe文件)。这应该会为您的异​​常生成更有意义的堆栈跟踪。

现在,第二部分。您需要将托管环境与本地环境区分开来。在 windbg 中,您正在调试操作系统所看到的 CLR,因此您不仅要调试 C# 应用程序,还要调试 CLR 解释器,该解释器将 ILASM(编译的 C# 代码)编译为本机 CPU 指令,然后执行它们。所以你比你通常在 VS 中看到的低一层(附加了托管调试器)。记住这一点,您需要深入了解 CLR 内部结构并尝试弄清楚寄存器中的地址是什么意思,或者使用某种翻译器来为您完成这项繁重的工作。这就是SOS 发挥作用的地方。设置断点时已经使用过它。由于您只对了解变量的值感兴趣,因此您需要首先找出 CLR 为您提供的地址。从我看到的_videoCameraType 是私人班级成员,不是吗?如果是这样,您可以使用!dso 命令从堆栈中转储托管对象。您应该会看到类似于以下输出的内容:

> !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

Program+Test 将替换为您的班级名称。然后您可以使用!do 命令和Object 列中的地址转储对象内容:

> !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

通过名称查找类成员并再次使用!do 命令,但使用Value 列中的地址(这适用于引用类型)。在我们的示例中,它将是:

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  <<

如果您需要弄清楚局部变量的值是什么,事情就会变得更加棘手。您可以尝试使用!CLRStack -a,它通常不会在发布版本中显示太多。然后,您将对生成的程序集 (!U @rip) 进行分析,以找出变量的地址位于何处(注册表、堆栈)。弄清楚这一点后,再次使用您找到的地址发出!do 命令。调试愉快:)

【讨论】:

【参考方案2】:

添加到此线程,因为它出现在 Google 搜索中:

以下内容对我有用:

(如果应用程序使用 .net 4 使用 .loadby sos clr 加载 SOS 调试器扩展)

一旦您在正确的线程上,首先使用 !clrstack -p 转储堆栈以及局部变量的地址。

现在使用 !do 使用感兴趣的局部变量的地址来转储它。

然后使用您获得的输出中的地址 - 您可以再次使用 !do(使用此处的 Value 字段作为特定成员的地址)。你可以继续,直到你能够看到你想要的价值。

(您也可以使用此方法转储从堆栈中获取的“this”指针的成员。根据您要查找的内容,这可能包含一些感兴趣的变量)

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

调试令人兴奋!玩得开心!

【讨论】:

以上是关于如何使用windbg查看c#变量的主要内容,如果未能解决你的问题,请参考以下文章

WinDbg链接

WinDbg链接

WINDBG,如何查看数组的内容?

通过查看Windbg中的变量值去定位C++软件异常问题

windbg 和cdbg使用总结

如何使用 windbg 检查堆转储上的静态 thread_local 变量的内容?