Basic Windbg - 2 CLR基础

调整一下写的思路,第一部分的sos basics继续有效,原定的crash/hang/memory等,序号顺延,中间插入这个clr basics

创建一个控制台程序,代码如下:

Code
using System;
using System.Collections.Generic;
using System.Text;

namespace HelloWindbg
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            Console.WriteLine(
\Hello, windbg!\);
            Console.ReadLine();
        }
    }
}


IDE中,按Ctrl+F5运行,等到显示出来\Hello, windbg!”之后(不要按回车),启动windbg,在窗口中按F6,此时出现一个process list窗口,向下找,找到这个hellowindbg.exe进程(名字是你project编译后的exe名字,不一定与我这个相同),然后点OK确定。此时windbg会显示类似信息:

(1270.11c4): Break instruction exception - code 80000003 (first chance)
eax=7ffdc000 ebx=00000000 ecx=00000000 edx=7786d094 esi=00000000 edi=00000000
eip=77827dfe esp=01bffbcc ebp=01bffbf8 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!DbgBreakPoint:
77827dfe cc              int     3

这时候,加载sos扩展,命令如下:.load clr20\sos.dll
好了,可以干活了!

首先看第一个命令,!dumpdomain,运行后,我们得到如下类似结果:

0:003> !dumpdomain
--------------------------------------
System Domain: 7a3bc8b8
LowFrequencyHeap: 7a3bc8dc
HighFrequencyHeap: 7a3bc934
StubHeap: 7a3bc98c
Stage: OPEN
Name: None
--------------------------------------
Shared Domain: 7a3bc560
LowFrequencyHeap: 7a3bc584
HighFrequencyHeap: 7a3bc5dc
StubHeap: 7a3bc634
Stage: OPEN
Name: None
Assembly: 003b9368
--------------------------------------
Domain 1: 00374ec0
LowFrequencyHeap: 00374ee4
HighFrequencyHeap: 00374f3c
StubHeap: 00374f94
Stage: OPEN
SecurityDescriptor: 00376420
Name: HelloWindbg.exe
Assembly: 003b9368 [C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader: 0036cd88
SecurityDescriptor: 003ae6e8
  Module Name
790c2000 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
001b239c C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sortkey.nlp
001b2010 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sorttbls.nlp

Assembly: 003cab78 [C:\Users\charju\Documents\Visual Studio 2008\Projects\Windbg\HelloWindbg\HelloWindbg\bin\Debug\HelloWindbg.exe]
ClassLoader: 0036ced8
SecurityDescriptor: 003caaf0
  Module Name
00192d8c C:\Users\charju\Documents\Visual Studio 2008\Projects\Windbg\HelloWindbg\HelloWindbg\bin\Debug\HelloWindbg.exe

对于上面的结果,我们有几个重要发现:
1
.net app默认情况下,会有三个AppDomain,其中分别是System DomainShared Domain和应用程序自己的Application Domain(就是上面的Domain 1)。
2
、一个domain内包含了一个或若干个assembly

对于每个具体的domain,都可以用!dumpdomain <domain assress>来看。比如这里的app domain,可以执行命令:!dumpdomain 00374ec0,结果就不贴了,和上面的显示是一致的。

这个app domain里面我们看到,包含了两个assembly,分别是mscorlib.dllhellowindbg.exe,前者包含了3module,后者包含了1module。这里我们看hellowindbg.exe的信息,对于mscorlib.dll,大家可以依据下面步骤做练习。

assmebly信息,命令式:!dumpassembly <assembly address>so,我们执行:!dumpassembly 003cab78(这个地址是上面的蓝色的那个数字),得到类似信息:

Parent Domain: 00374ec0
Name: C:\Users\charju\Documents\Visual Studio 2008\Projects\Windbg\HelloWindbg\HelloWindbg\bin\Debug\HelloWindbg.exe
ClassLoader: 0036ced8
SecurityDescriptor: 018c4448
  Module Name
00192d8c C:\Users\charju\Documents\Visual Studio 2008\Projects\Windbg\HelloWindbg\HelloWindbg\bin\Debug\HelloWindbg.exe

这里有几个地方可以注意:
1
assembly包含了指向domain的信息,上面的:00374ec0
2
assembly包含了一个或者若干个module

这里只有一个module,我们继续看module里面包含啥,结果从略(我们这里不关心它)。
命令!dumpmodule有一个有用的开关,是-mt <mt address>,我们跑一下看看:!dumpmodule -mt 1caa50

0:003> !dumpmodule -mt 00192d8c
Name: C:\Users\charju\Documents\Visual Studio 2008\Projects\Windbg\HelloWindbg\HelloWindbg\bin\Debug\HelloWindbg.exe
Attributes: PEFile
Assembly: 003cab78
LoaderHeap: 00000000
TypeDefToMethodTableMap: 00190148
TypeRefToMethodTableMap: 00190150
MethodDefToDescMap: 0019019c
FieldDefToDescMap: 001901a8
MemberRefToDescMap: 001901ac
FileReferencesMap: 001901f8
AssemblyReferencesMap: 001901fc
MetaData start address: 000b206c (1456 bytes)

Types defined in this module

      MT    TypeDef Name
------------------------------------------------------------------------------
00193180 0x02000002 HelloWindbg.Program

Types referenced in this module

      MT    TypeRef Name
------------------------------------------------------------------------------
790fd0f0 0x01000001 System.Object
79101118 0x01000012 System.Console

我们能发现两个重要的东西:
1
、这个module里面包含的types,这里是我们的程序主入口点:HelloWindbg.Program
2
、这个module引用的types,这里是objectConsole

看上面的HelloWindbg.Program,这个type对应的MethodTable地址是:00193180。我们可以继续看这个MethodTable包含啥东西:

0:003> !dumpmt 00193180
EEClass: 001912e4
Module: 00192d8c
Name: HelloWindbg.Program
mdToken: 02000002  (C:\Users\charju\Documents\Visual Studio 2008\Projects\Windbg\HelloWindbg\HelloWindbg\bin\Debug\HelloWindbg.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 6

这里有一些重要的东西可以看:
1
EEClass,可以通过!dumpclass <class address>来查看这个class的信息。如:!dumpclass 001912e4
2、包含了Modulename等信息
3
、包含了Method Description 信息
4
VTable里面的slots一共6个。

MethodTable
只是一个入口表,它实际指向了一堆Method Description,那么我们可以用!dumpmt继续来查看,只不过参数要修改一下:!dumpmt -md 00193180

0:003> !dumpmt -md 00193180
EEClass: 001912e4
Module: 00192d8c
Name: HelloWindbg.Program
mdToken: 02000002  (C:\Users\charju\Documents\Visual Studio 2008\Projects\Windbg\HelloWindbg\HelloWindbg\bin\Debug\HelloWindbg.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 6
--------------------------------------
MethodDesc Table
   Entry MethodDesc      JIT Name
79371278   7914b928   PreJIT System.Object.ToString()
7936b3b0   7914b930   PreJIT System.Object.Equals(System.Object)
7936b3d0   7914b948   PreJIT System.Object.GetHashCode()
793624d0   7914b950   PreJIT System.Object.Finalize()
00330070   00193170      JIT HelloWindbg.Program.Main(System.String[])
0019c01c   00193178     NONE HelloWindbg.Program..ctor()

注意---------------------以上的部分,和我们不加-md参数效果是一样的,下面多出来了6method description的信息,这就是那个Slots in VTable:6里面的6

对于每个方法,上表有一列JIT指明了CLR是否已经对该方法进行了compile动作。上面有一个方法是JIT过了,是那个Main函数,另外的4CLR已经预先做了JIT(为什么?想想GACNGEN.EXE)。那么对于具体的方法是否做过了JIT,我们可以用命令:!dumpmd来看,比如看上面的Main方法,那么!dumpmd 00193170

0:003> !dumpmd 00193170     
Method Name: HelloWindbg.Program.Main(System.String[])
Class: 001912e4
MethodTable: 00193180
mdToken: 06000001
Module: 00192d8c
IsJitted:
yes
m_CodeOrIL: 00330070 text here

上面最重要的结果就是有一个IsJitted的标志,这里是yes,表明它已经被compile过了,对于compile之后的native code,我们就可以用命令!u <m_codeoril>来观察。下命令:!u 00330070,如下代码:

0:003> !u 00330070
Normal JIT generated code
HelloWindbg.Program.Main(System.String[])
Begin 00330070, size 28
>>> 00330070 50              push    eax
00330071 890c24          mov     dword ptr [esp],ecx
00330074 833d582f190000  cmp     dword ptr ds:[192F58h],0
0033007b 7405            je      HelloWindbg!HelloWindbg.Program.Main(System.String[])+0x12 (00330082)
0033007d e8c582df79      call    mscorwks!JIT_DbgIsJustMyCode (7a128347)
00330082 90              nop
00330083 8b0d4030d602    mov     ecx,dword ptr ds:[2D63040h] (\Hello, windbg!\)
00330089 e8c69c0b79      call    mscorlib_ni!System.Console.WriteLine(System.String) (793e9d54)
0033008e 90              nop
0033008f e850990b79      call    mscorlib_ni!System.Console.ReadLine() (793e99e4)
00330094 90              nop
00330095 90              nop
00330096 59              pop     ecx
00330097 c3              ret

类似的,我们可以!dumpmd 00193178,看到该方法并没有被compile(现在),native code自然也没有生成:

0:003> !dumpmd 00193178
Method Name: HelloWindbg.Program..ctor()
Class: 001912e4
MethodTable: 00193180
mdToken: 06000002
Module: 00192d8c
IsJitted:
no
m_CodeOrIL:
ffffffff

好了,对于appdomain/assembly/module/method table(class)/method description,这里做了一个简单的research,我们看点别的。

0:000> !clrstack
OS Thread Id: 0x12d0 (0)
ESP       EIP    
002bf148 77839a94 [NDirectMethodFrameStandaloneCleanup: 002bf148] System.IO.__ConsoleStream.ReadFile(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
002bf164 7948d2bb System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Int32, Int32 ByRef)
002bf190 7948d1ed System.IO.__ConsoleStream.Read(Byte[], Int32, Int32)
002bf1b0 793a3350 System.IO.StreamReader.ReadBuffer()
002bf1c0 793aaa2f System.IO.StreamReader.ReadLine()
002bf1d4 79497b5a System.IO.TextReader+SyncTextReader.ReadLine()
002bf1dc 793e99f0 System.Console.ReadLine()
002bf1e0 00330094 HelloWindbg.Program.Main(System.String[])
002bf404 79e7c74b [GCFrame: 002bf404]


这里列出来的都是一些name,比如说我想看StreamReader里面有哪些方法,怎么看呢?
1
、转换:用命令!name2ee <modulename>!<type or method name>。那么,module name是什么呢?我们要用lm来看一眼,加上一点clr的知识:

0:000> lm
start    end        module name
000b0000 000b8000   HelloWindbg C (private pdb symbols)  C:\Users\charju\Documents\Visual Studio 2008\Projects\Windbg\HelloWindbg\HelloWindbg\bin\Debug\HelloWindbg.pdb
75070000 7520e000   comctl32   (deferred)            
75310000 753ab000   MSVCR80    (deferred)            
761f0000 762cb000   KERNEL32   (pdb symbols)          c:\symcache\kernel32.pdb\093FA0AF6A7B4CE9B12506584036EC882\kernel32.pdb
762d0000 76328000   SHLWAPI    (deferred)            
764b0000 7654d000   USER32     (deferred)            
76610000 7662e000   IMM32      (deferred)            
766c0000 7676a000   msvcrt     (deferred)            
76770000 767bb000   GDI32      (deferred)            
767c0000 76883000   RPCRT4     (deferred)            
76890000 76956000   ADVAPI32   (deferred)            
76ab0000 775bf000   shell32    (deferred)            
775c0000 77688000   MSCTF      (deferred)            
77690000 777d4000   ole32      (deferred)            
777e0000 77907000   ntdll      (pdb symbols)          c:\symcache\ntdll.pdb\B958B2F91A5A46B889DAFAB4D140CF252\ntdll.pdb
77910000 77919000   LPK        (deferred)            
779c0000 77a3d000   USP10      (deferred)            
79000000 79046000   mscoree    (pdb symbols)          c:\symcache\mscoree.pdb\B3B672BC69034D0F8EF2A40525E64BDE2\mscoree.pdb
79060000 790b6000   mscorjit   (deferred)            
790c0000 79bf6000   mscorlib_ni C (pdb symbols)          c:\symcache\mscorlib.pdb\446AC27A973142A6900EEAF1E9EC50451\mscorlib.pdb
79e70000 7a3ff000   mscorwks   (pdb symbols)          c:\symcache\mscorwks.pdb\8BDE5914A40043B3BCC3E7F49A6C29D22\mscorwks.pdb

最终决定用这个命令:!name2ee mscorlib_ni!System.IO.StreamReader.ReadBuffer,得到下面结果:

Module: 790c2000 (mscorlib.dll)
Token: 0x06003622
MethodDesc:
7926c0a0
Name: System.IO.StreamReader.ReadBuffer()
JITTED Code Address: 793a32f4
-----------------------
Token: 0x06003623
MethodDesc: 7926c0a8
Name: System.IO.StreamReader.ReadBuffer(Char[], Int32, Int32, Boolean ByRef)
JITTED Code Address: 79498020

好了,可以走第二步了,因为上面已经拿到了Method Description的地址了,跑!dumpmd 7926c0a0,如下:

0:000> !dumpmd 7926c0a0
Method Name: System.IO.StreamReader.ReadBuffer()
Class: 7911b210
MethodTable:
7911b288
mdToken: 06003622
Module: 790c2000
IsJitted: yes
m_CodeOrIL: 793a32f4

看到了上面的Method table地址了没?用!dumpmt -md 7911b288,可以得到这个class的所有method信息(结果从略,大家做练习吧!)

(累死我了。。。园子这个post编辑上工具条上的Insert Layer,不好用。结构都乱了!只好重新修改一次)

posted @ 2008-03-04 20:01 鞠强 阅读(...) 评论(...) 编辑 收藏

hello

world