2013-07-18 44 views
2

我在我想調試的32位Windows Server 2003計算機上安裝了C#windows服務。如何使用windbg查看c#變量

我的問題是,一個日誌文件中的錯誤消息告訴我下面的:

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); 
      } 
    }   
  1. 我已經打開的WinDbg和沒有文件 - >附加到進程
  2. 我在功能設置使用上述這裏列出的步驟斷點:http://blogs.msdn.com/b/alejacma/archive/2009/07/13/managed-debugging-with-windbg-preparing-the-environment.aspx
  3. 當斷點被擊中我走上前使用F10,但我看到的是這樣的:

    設置斷點:BP 05A0A260 [,視頻處理器。 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>點 EAX = 00000001 EBX = 00902870 ECX = 00a1e020 EDX = 01066e78 ESI = 00affb48 EDI = 0106 6e78 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,尤 0:024>點 EAX = 00000001 EBX = 00902870 ECX = 00a1e020 EDX = 01066e78 ESI = 00affb48 EDI = 01066e78 EIP = 05a0a263 ESP = 0674e688 EBP = 0674e688 IOPL = 0 NV向上EI PL NZ NA PO NC CS = 001B SS = 0023 DS = 0023 ES = 0023 FS = 003B GS = 0000 EFL = 00000202 05a0a263 57推EDI

這意味着目前nothign到我(我是一個WinDBG的新手)

  1. 我對窗口服務(我從Visual Studio調試輸出文件夾了),並在一個文件夾ç複製ITTO我的目標機器PDB文件:\符號
  2. 在WinDbg中我做了文件 - >符號文件路徑並將其設置爲我複製此PDB文件的位置。我的符號路徑如下: C:\ symcache; C:\符號; SRV * C:\ * symcache http://msdl.microsoft.com/download/symbols
  3. 在WinDbg中我做了視圖 - >觀看和我的名字輸入一個變量在上面的函數中(videoCameraType)。但我得到了以下錯誤:


    * * * * 要麼你指定一個不合格的符號,或者您的調試器 *沒有完全的符號信息。不合格符號* 分辨率默認爲關閉。請要麼指定 *完全合格的符號模塊!符號名稱,或鍵入」 .symopt- 100" 使分辨率不合格符號* 。需要注意的是 *能夠在符號路徑* 服務器共享網絡符號不合格的符號分辨率可能導致調試器 *似乎掛起了很長一段時間,當一個不正確的* 符號名稱已鍵入或網絡符號服務器已關閉。 ** 對於一些命令才能正常工作,你的符號路徑 *必須指向.PDB有完整的類型信息的文件。 * *某些.pdb文件(如公共操作系統符號)不* 包含所需信息。聯繫該 *爲您提供了這些符號,如果你需要這個命令* 工作組。 ** *類型引用:_videoCameraType * * *


如何查看變量,通常看到什麼是在我的代碼怎麼回事??? ? 我也有Windows服務的源代碼,如果這有什麼幫助。

感謝

回答

7

第一件事情是,因爲在你的異常堆棧跟蹤沒有源文件路徑和行號的符號文件可能不匹配的二進制文件。你提到你是從Visual Studio調試輸出中複製它們的,所以我假設你有在Release中編譯的二進制文件(沒有符號)和Debug中的pdb文件。這不起作用。你需要做的是change the project settings for your service,重新編譯並部署它(你現在應該在發佈輸出文件夾中有pdb,dll和exe文件)。這應該爲您的異常生成更有意義的堆棧跟蹤。

現在,第二部分。你需要區分一個託管環境和本地託管環境。在windbg中,您正在調試CLR,因爲它正在被操作系統看到,因此您不僅調試C#應用程序,還調試將您的ILASM(已編譯的C#代碼)編譯爲本地CPU指令並執行它們的CLR解釋器。所以你是一個低於你通常在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命令和你找到的地址。快樂調試:)

1

添加到這個線程,因爲它出現在谷歌搜索:

以下爲我工作:

(如果應用程序使用.NET 4中使用.loadby SOS CLR加載SOS調試器擴展)

一旦你在正確的線程上,首先使用!clrstack -p轉儲堆棧以及本地變量的地址。

現在使用感興趣的局部變量的地址來轉儲它使用!做。

然後使用您獲得的輸出中的地址 - 您可以使用!再次執行(在此處使用值字段作爲特定成員的地址)。你可以繼續下去,直到你能夠看到你想要的價值。

(你也可以用這種方法來轉儲「this」指針的成員,你從堆棧中獲得,這可能會對你在找什麼興趣基地的一些變量)

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

調試很刺激!玩得開心!