3 进程与线程
既可以显示进程和线程列表,又可以显示指定进程或线程的详细信息。调试命令可以提供比taskmgr更详尽的进程资料,在调试过程中不可或缺。
3.1 进程命令
进程命令包括这些内容:显示进程列表、进程环境块、设置进程环境。
进程列表
多个命令可显示进程列表,但一般只能在特定情况下使用,它们是:|、.tlist、!process和!dml_proc。
竖线命令显示当前被调试进程列表的状态信息,这个命令在本章开头已作过介绍,命令格式如下:
§ | [进程号]
请注意这里的定语:被调试进程列表。大多数情况下调试器中只有一个被调试进程,但可以通过.attach或者.create命令同时挂载或创建多个调试对象。当同时对多个进程调试时,进程号是从0开始的整数。下图中显示了两个被调试的进程。
0:004> |
. 0 id: 1c80 examine name: C:\Users\winne\Documents\Visual Studio 2008\Projects\ttt\x64\Debug\ttt.exe
§ .tlist [选项] [模块名]
.tlist命令显示当前系统中的进程列表,他是目前唯一可在用户模式下显示系统当前进程列表的命令。它有两个可选项:-v显示进程详细信息,-c只显示当前进程信息。
内核模式下同样可以使用.tlist,但更好的命令是!process。!process在内核模式下显示进程列表,和指定进程的详细信息,也能显示进程中的线程和调用栈内容。典型格式如下:
§ !process: 显示调试器当前运行进程信息
0:004> !dml_proc 0x0
DbgId PID Image file name
0 1c80 ...\Visual Studio 2008\Projects\ttt\x64\Debug\ttt.exe
Browse module list
Threads:
DbgId TID Name (if available)
0 2edc
1 7274
2 84f0
3 85ec
4 bf78
5 1674
此外,还有一个DML版本的进程列表命令,如下:
§ !dml_proc [进程号|进程地址]
此命令可以看成“|”和“!process”命令的DML合并版本,可在用户与内核模式下使用。显示的进程信息偏重于线程和调用栈。用户模式下此命令和“|”一样,只能显示被调试进程的信息。右图是内核模式下使用此命令的效果:
进程信息
进程环境块(Process Enviroment Block)是内核结构体,使用!peb命令参看其信息,但也可以用dt命令查看完整的结构体定义。格式如下:
§ !peb [地址]
如果未设置PEB地址,则默认为当前进程。内核模式下可通过!process命令获取PEB结构体地址;用户模式下只能显示当前进程的PEB信息,故而一般不带参数。
0:004> !peb
PEB at 0000000000aff000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: Yes
ImageBaseAddress: 00007ff7160d0000
Ldr 00007ffe7144b340
Ldr.Initialized: Yes
Ldr.InInitializationOrderModuleList: 0000000002db28b0 . 0000000002db4b50
Ldr.InLoadOrderModuleList: 0000000002db2a60 . 0000000002dbbc90
Ldr.InMemoryOrderModuleList: 0000000002db2a70 . 0000000002dbbca0
Base TimeStamp Module
7ff7160d0000 5a449c9b Dec 28 15:26:19 2017 C:\Users\winne\Documents\Visual Studio 2008\Projects\ttt\x64\Debug\ttt.exe
7ffe712f0000 8274fd8b May 11 13:39:23 2039 C:\Windows\SYSTEM32\ntdll.dll
7ffe6f2a0000 f5fa43df Oct 10 10:41:35 2100 C:\Windows\System32\KERNEL32.DLL
7ffe6e330000 1a9bbe0b Feb 24 03:59:07 1984 C:\Windows\System32\KERNELBASE.dll
72c60000 488ef62b Jul 29 18:51:23 2008 C:\Windows\WinSxS\amd64_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.30729.1_none_737233ca1c100ce5\MSVCP90D.dll
72d80000 488ef626 Jul 29 18:51:18 2008 C:\Windows\WinSxS\amd64_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.30729.1_none_737233ca1c100ce5\MSVCR90D.dll
6fd20000 53828c7e May 26 08:36:14 2014 C:\Qt\4.8.4\bin\QtGuid4.dll
70fd0000 53828953 May 26 08:22:43 2014 C:\Qt\4.8.4\bin\QtCored4.dll
7ffe6ef30000 6d9de53a Apr 11 19:12:58 2028 C:\Windows\System32\USER32.dll
7ffe6faf0000 efcc154c Jun 27 07:57:00 2097 C:\Windows\System32\GDI32.dll
7ffe6e6e0000 d9592a17 Jul 21 04:29:11 2085 C:\Windows\System32\win32u.dll
7ffe6e1a0000 298bec01 Feb 02 21:02:57 1992 C:\Windows\System32\gdi32full.dll
7ffe6e700000 d867caf3 Jan 19 02:26:59 2085 C:\Windows\System32\msvcp_win.dll
7ffe6ed40000 cf17fc6c Feb 06 22:34:20 2080 C:\Windows\System32\ole32.dll
7ffe6e580000 8ac9f9d4 Oct 15 11:28:20 2043 C:\Windows\System32\ucrtbase.dll
7ffe6f590000 b66dc19d Dec 27 11:31:41 2066 C:\Windows\System32\combase.dll
7ffe6fd80000 20fe5196 Jul 18 00:32:22 1987 C:\Windows\System32\RPCRT4.dll
7ffe6f080000 64f6792a Sep 05 08:41:14 2023 C:\Windows\System32\COMDLG32.dll
7ffe6df10000 535124ab Apr 18 21:12:11 2014 C:\Windows\System32\bcryptPrimitives.dll
7ffe6ee90000 3280d1b7 Nov 07 01:58:15 1996 C:\Windows\System32\msvcrt.dll
7ffe6f960000 b4c11302 Feb 05 07:36:34 2066 C:\Windows\System32\sechost.dll
7ffe6ec90000 a64bfd9f May 30 23:26:23 2058 C:\Windows\System32\shcore.dll
7ffe6f8b0000 46b92c26 Aug 08 10:36:22 2007 C:\Windows\System32\ADVAPI32.dll
7ffe6f190000 166c812d Dec 03 14:41:49 1981 C:\Windows\System32\SHLWAPI.dll
7ffe6f380000 60cde072 Jun 19 20:17:54 2021 C:\Windows\System32\WS2_32.dll
7ffe6feb0000 c3faa15c Mar 11 16:27:08 2074 C:\Windows\System32\SHELL32.dll
7ffe6df80000 bb524065 Aug 03 12:30:29 2069 C:\Windows\System32\cfgmgr32.dll
7ffe6d810000 c007cd3b Feb 03 22:52:43 2072 C:\Windows\System32\windows.storage.dll
7ffe488d0000 8b5b80d8 Feb 02 20:43:04 2044 C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_5.82.15063.413_none_0e0f5dcc67adff4e\COMCTL32.dll
7ffe6d7d0000 ed031ad5 Jan 03 12:34:29 2096 C:\Windows\System32\kernel.appcore.dll
7ffe6d780000 bc0704c4 Dec 18 15:16:20 2069 C:\Windows\System32\powrprof.dll
7ffe6d760000 c8e1d59a Oct 18 18:44:42 2076 C:\Windows\System32\profapi.dll
7ffe6f9d0000 98823ee8 Jan 30 14:23:36 2051 C:\Windows\System32\OLEAUT32.dll
7ffe6f350000 dd2e6bc9 Aug 04 11:43:05 2087 C:\Windows\System32\IMM32.dll
7ffe44480000 b555e731 May 29 04:57:21 2066 C:\Windows\SYSTEM32\WINSPOOL.DRV
7ffe6c290000 24ec155f Aug 18 21:55:43 1989 C:\Windows\SYSTEM32\WINMM.dll
7ffe6c260000 318335b4 Apr 28 17:09:08 1996 C:\Windows\SYSTEM32\WINMMBASE.dll
7ffe6d400000 17fe17fb Oct 04 05:24:11 1982 C:\Windows\SYSTEM32\bcrypt.dll
SubSystemData: 0000000000000000
ProcessHeap: 0000000002db0000
ProcessParameters: 0000000002db1f00
CurrentDirectory: 'C:\Users\winne\Documents\Visual Studio 2008\Projects\ttt\x64\Debug\'
WindowTitle: 'C:\Users\winne\Documents\Visual Studio 2008\Projects\ttt\x64\Debug\ttt.exe'
ImageFile: 'C:\Users\winne\Documents\Visual Studio 2008\Projects\ttt\x64\Debug\ttt.exe'
CommandLine: '"C:\Users\winne\Documents\Visual Studio 2008\Projects\ttt\x64\Debug\ttt.exe" '
DllPath: '< Name not readable >'
Environment: 0000000002db10d0
=::=::\
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\winne\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
COMPUTERNAME=DESKTOP-IUA9ONQ
ComSpec=C:\Windows\system32\cmd.exe
DEVELOP_HOME=D:\D6000-Develop\V2.0\source
HOMEDRIVE=C:
HOMEPATH=\Users\winne
LOCALAPPDATA=C:\Users\winne\AppData\Local
LOGONSERVER=\\DESKTOP-IUA9ONQ
NBENV=D:\d6000\d6000\d6000
NUMBER_OF_PROCESSORS=8
OneDrive=C:\Users\winne\OneDrive
ORACLE_HOME=f:\oracle\product\11.2.0\dbhome_1
OS=Windows_NT
Path=f:\oracle\product\11.2.0\dbhome_1\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Qt\4.8.4\\bin;C:\Qt\4.8.4\\lib;c:\Program Files (x86)\Microsoft SQL Server\90\Tools\binn\;D:\d6000\d6000\d6000\bin;D:\d6000\d6000\d6000\dll;D:\d6000\d6000\d6000\protocol;C:\Users\winne\AppData\Local\Microsoft\WindowsApps;
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=AMD64
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 58 Stepping 9, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=3a09
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
ProgramFiles(x86)=C:\Program Files (x86)
ProgramW6432=C:\Program Files
PSModulePath=C:\Program Files\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules
PUBLIC=C:\Users\Public
QTDIR=C:\Qt\4.8.4\
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\Windows
TEMP=C:\Users\winne\AppData\Local\Temp
TMP=C:\Users\winne\AppData\Local\Temp
USERDOMAIN=DESKTOP-IUA9ONQ
USERDOMAIN_ROAMINGPROFILE=DESKTOP-IUA9ONQ
USERNAME=Jack-PC
USERPROFILE=C:\Users\winne
VS90COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\
windir=C:\Windows
§ dt nt!_peb 地址
此命令显示系统nt模块中所定义的内核结构体PEB详细内容。使用之前必须先熟悉结构体定义。
0:004> dt nt!_peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 BitField : UChar
+0x003 ImageUsesLargePages : Pos 0, 1 Bit
+0x003 IsProtectedProcess : Pos 1, 1 Bit
+0x003 IsImageDynamicallyRelocated : Pos 2, 1 Bit
+0x003 SkipPatchingUser32Forwarders : Pos 3, 1 Bit
+0x003 IsPackagedProcess : Pos 4, 1 Bit
+0x003 IsAppContainer : Pos 5, 1 Bit
+0x003 IsProtectedProcessLight : Pos 6, 1 Bit
+0x003 IsLongPathAwareProcess : Pos 7, 1 Bit
+0x004 Padding0 : [4] UChar
+0x008 Mutant : Ptr64 Void
+0x010 ImageBaseAddress : Ptr64 Void
+0x018 Ldr : Ptr64 _PEB_LDR_DATA
+0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
+0x028 SubSystemData : Ptr64 Void
+0x030 ProcessHeap : Ptr64 Void
+0x038 FastPebLock : Ptr64 _RTL_CRITICAL_SECTION
+0x040 AtlThunkSListPtr : Ptr64 _SLIST_HEADER
+0x048 IFEOKey : Ptr64 Void
+0x050 CrossProcessFlags : Uint4B
+0x050 ProcessInJob : Pos 0, 1 Bit
+0x050 ProcessInitializing : Pos 1, 1 Bit
+0x050 ProcessUsingVEH : Pos 2, 1 Bit
+0x050 ProcessUsingVCH : Pos 3, 1 Bit
+0x050 ProcessUsingFTH : Pos 4, 1 Bit
+0x050 ProcessPreviouslyThrottled : Pos 5, 1 Bit
+0x050 ProcessCurrentlyThrottled : Pos 6, 1 Bit
+0x050 ReservedBits0 : Pos 7, 25 Bits
+0x054 Padding1 : [4] UChar
+0x058 KernelCallbackTable : Ptr64 Void
+0x058 UserSharedInfoPtr : Ptr64 Void
+0x060 SystemReserved : [1] Uint4B
+0x064 AtlThunkSListPtr32 : Uint4B
+0x068 ApiSetMap : Ptr64 Void
+0x070 TlsExpansionCounter : Uint4B
+0x074 Padding2 : [4] UChar
+0x078 TlsBitmap : Ptr64 Void
+0x080 TlsBitmapBits : [2] Uint4B
+0x088 ReadOnlySharedMemoryBase : Ptr64 Void
+0x090 SharedData : Ptr64 Void
+0x098 ReadOnlyStaticServerData : Ptr64 Ptr64 Void
+0x0a0 AnsiCodePageData : Ptr64 Void
+0x0a8 OemCodePageData : Ptr64 Void
+0x0b0 UnicodeCaseTableData : Ptr64 Void
+0x0b8 NumberOfProcessors : Uint4B
+0x0bc NtGlobalFlag : Uint4B
+0x0c0 CriticalSectionTimeout : _LARGE_INTEGER
+0x0c8 HeapSegmentReserve : Uint8B
+0x0d0 HeapSegmentCommit : Uint8B
+0x0d8 HeapDeCommitTotalFreeThreshold : Uint8B
+0x0e0 HeapDeCommitFreeBlockThreshold : Uint8B
+0x0e8 NumberOfHeaps : Uint4B
+0x0ec MaximumNumberOfHeaps : Uint4B
+0x0f0 ProcessHeaps : Ptr64 Ptr64 Void
+0x0f8 GdiSharedHandleTable : Ptr64 Void
+0x100 ProcessStarterHelper : Ptr64 Void
+0x108 GdiDCAttributeList : Uint4B
+0x10c Padding3 : [4] UChar
+0x110 LoaderLock : Ptr64 _RTL_CRITICAL_SECTION
+0x118 OSMajorVersion : Uint4B
+0x11c OSMinorVersion : Uint4B
+0x120 OSBuildNumber : Uint2B
+0x122 OSCSDVersion : Uint2B
+0x124 OSPlatformId : Uint4B
+0x128 ImageSubsystem : Uint4B
+0x12c ImageSubsystemMajorVersion : Uint4B
+0x130 ImageSubsystemMinorVersion : Uint4B
+0x134 Padding4 : [4] UChar
+0x138 ActiveProcessAffinityMask : Uint8B
+0x140 GdiHandleBuffer : [60] Uint4B
+0x230 PostProcessInitRoutine : Ptr64 void
+0x238 TlsExpansionBitmap : Ptr64 Void
+0x240 TlsExpansionBitmapBits : [32] Uint4B
+0x2c0 SessionId : Uint4B
+0x2c4 Padding5 : [4] UChar
+0x2c8 AppCompatFlags : _ULARGE_INTEGER
+0x2d0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x2d8 pShimData : Ptr64 Void
+0x2e0 AppCompatInfo : Ptr64 Void
+0x2e8 CSDVersion : _UNICODE_STRING
+0x2f8 ActivationContextData : Ptr64 _ACTIVATION_CONTEXT_DATA
+0x300 ProcessAssemblyStorageMap : Ptr64 _ASSEMBLY_STORAGE_MAP
+0x308 SystemDefaultActivationContextData : Ptr64 _ACTIVATION_CONTEXT_DATA
+0x310 SystemAssemblyStorageMap : Ptr64 _ASSEMBLY_STORAGE_MAP
+0x318 MinimumStackCommit : Uint8B
+0x320 FlsCallback : Ptr64 _FLS_CALLBACK_INFO
+0x328 FlsListHead : _LIST_ENTRY
+0x338 FlsBitmap : Ptr64 Void
+0x340 FlsBitmapBits : [4] Uint4B
+0x350 FlsHighIndex : Uint4B
+0x358 WerRegistrationData : Ptr64 Void
+0x360 WerShipAssertPtr : Ptr64 Void
+0x368 pUnused : Ptr64 Void
+0x370 pImageHeaderHash : Ptr64 Void
+0x378 TracingFlags : Uint4B
+0x378 HeapTracingEnabled : Pos 0, 1 Bit
+0x378 CritSecTracingEnabled : Pos 1, 1 Bit
+0x378 LibLoaderTracingEnabled : Pos 2, 1 Bit
+0x378 SpareTracingBits : Pos 3, 29 Bits
+0x37c Padding6 : [4] UChar
+0x380 CsrServerReadOnlySharedMemoryBase : Uint8B
+0x388 TppWorkerpListLock : Uint8B
+0x390 TppWorkerpList : _LIST_ENTRY
+0x3a0 WaitOnAddressHashTable : [128] Ptr64 Void
进程切换
进程环境的切换,将伴随着与进程相关的寄存器、堆栈的切换。在不同进程环境中进行的调试结果有天壤之别。上文在讲“|”命令的时候,讲过用户环境下多进程间如何互相切换,使用命令:
§ | [进程号] s
那么内核模式下,情况又不同了。内核模式下的进程切换,不同于用户模式下的被调试进程间切换,而是系统存在的多进程间切换。内核环境下,以进程地址作为参数,调用如下命令以进行进程环境切换:
§ .process [进程地址]
如果不使用任何参数,.process命令将显示当前进程地址。所谓进程地址,即ERPCESS结构体地址。
或以页目录地址为参数,调用下面命令切换用户地址空间:
§ .context [页目录地址]
如果不使用任何参数,.context命令将显示当前页目录地址。页目录地址就是!process命令中显示的DirBase值。
进程切换后,为了检测是否正确切换,可再用!peb命令检查当前进程的环境信息。
线程命令
命令“~”能够进行线程相关的操作。不带任何参数的情况下,它列出当前调试进程的线程。下图是计算器进程某时刻的线程列表:
0:004> ~线程冰冻
参数f与u分别代表freeze和unfress,前者是指冻住指定线程,后者将被冰冻线程解冻。
§ ~2f
表示把2号线程冻住,在解冻之前,不再分发CPU时间给它。
若要让指定线程重新运行,需使用参数u:
§ ~2u
针对这两个命令,下面有一个小实验运行Windbg,并选择调试记事本程序(Notepad.exe)。程序起来后,CTL+BREAK中断程序运行,输入命令:
~0f
再输入g命令让记事本继续运行。
此时尝试用鼠标定位到notepad软件,发现软件界面无法被定位、移动、最大小化,甚至“清空桌面”操作也无济于事。这是因为0号线程为notepad的主线程,被冻住后整个软件都失去响应。
更严重的是,“清空桌面”操作(Win + D)也会失效,应是Notepad拒绝响应的缘故。
线程挂起
参数n和m分别代表increase和resume,前者增加一个线程挂起计数,后者减少一个线程挂起计数。如果两次增加线程挂起计数(即达到2),则必须两次resume才能让线程恢复到运行状态。
把上面实验中的~0f命令改变成~0n,也能达到相似的效果。
线程切换
查看指定线程的信息,用下面的命令:
§ ~ 线程号
线程号是由调试器软件内部维护的线程ID值,是一个从0开始的整数,和线程ID不是一回事。
线程信息中包括有线程环境块地址,可通过!teb命令查看环境块信息:
§ !teb [teb地址]
如要在多线程间作切换,需使用~命令的s参数:
§ ~ 线程号 s
由于线程号在外部是没有太大意义的,所以另一个线程切换命令是以线程ID来标识一个线程的。这个命令比较奇怪,以双波浪线打头,格式如下:
§ ~~[线程ID] s
注意这个命令中的[]并非可选符,而是命令的一部分。例如命令:~~[11a0] s,它将当前线程切换到线程ID为0x11a0的线程。线程ID是系统维护的系统唯一的ID值。
0:001> ~
0 Id: 1c80.2edc Suspend: 1 Teb: 00000000`00b00000 Unfrozen
. 1 Id: 1c80.7274 Suspend: 1 Teb: 00000000`00b02000 Unfrozen
2 Id: 1c80.84f0 Suspend: 1 Teb: 00000000`00b04000 Unfrozen
3 Id: 1c80.85ec Suspend: 1 Teb: 00000000`00b06000 Unfrozen
# 4 Id: 1c80.bf78 Suspend: 1 Teb: 00000000`00b0a000 Unfrozen
5 Id: 1c80.1674 Suspend: 1 Teb: 00000000`00b0c000 Unfrozen
0:003> ~
0 Id: 1c80.2edc Suspend: 1 Teb: 00000000`00b00000 Unfrozen
1 Id: 1c80.7274 Suspend: 1 Teb: 00000000`00b02000 Unfrozen
2 Id: 1c80.84f0 Suspend: 1 Teb: 00000000`00b04000 Unfrozen
. 3 Id: 1c80.85ec Suspend: 1 Teb: 00000000`00b06000 Unfrozen
# 4 Id: 1c80.bf78 Suspend: 1 Teb: 00000000`00b0a000 Unfrozen
5 Id: 1c80.1674 Suspend: 1 Teb: 00000000`00b0c000 Unfrozen
第一个命令“~”运行时,当前线程是14号线程,请注意1号线程前面有一小点;运行第二个命令,将当前线程切换为3号线程;为了检验结果,再次运行“~”命令,此时注意到小点移到9号线程前,表明9号线程为当前线程。
§ ~*k
显示所有线程栈信息(此命令意指:对所有线程执行k指令)。下图中,当前进程共包含两个线程,显示了这两个线程各自的栈信息:
0:003> ~*k
0 Id: 1c80.2edc Suspend: 1 Teb: 00000000`00b00000 Unfrozen
Child-SP RetAddr Call Site
00000000`00d3f528 00007ffe`6e37dcb0 ntdll!ZwWaitForMultipleObjects+0x14
00000000`00d3f530 00007ffe`6e37dbae KERNELBASE!WaitForMultipleObjectsEx+0xf0
00000000`00d3f830 00007ff7`160d164c KERNELBASE!WaitForMultipleObjects+0xe
00000000`00d3f870 00007ff7`160d65e1 ttt!main+0x11c [c:\users\winne\documents\visual studio 2008\projects\ttt\ttt\main.cpp @ 49]
00000000`00d3f8f0 00007ff7`160d5de2 ttt!WinMain+0xb1 [c:\qt\4.8.4\src\winmain\qtmain_win.cpp @ 131]
00000000`00d3f960 00007ff7`160d5ade ttt!__tmainCRTStartup+0x2f2 [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crtexe.c @ 578]
00000000`00d3fa50 00007ffe`6f2b2774 ttt!WinMainCRTStartup+0xe [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crtexe.c @ 403]
00000000`00d3fa80 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`00d3fab0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
1 Id: 1c80.7274 Suspend: 1 Teb: 00000000`00b02000 Unfrozen
Child-SP RetAddr Call Site
00000000`0307fc18 00007ffe`71331553 ntdll!ZwWaitForWorkViaWorkerFactory+0x14
00000000`0307fc20 00007ffe`6f2b2774 ntdll!TppWorkerThread+0x293
00000000`0307ff30 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`0307ff60 00000000`00000000 ntdll!RtlUserThreadStart+0x21
2 Id: 1c80.84f0 Suspend: 1 Teb: 00000000`00b04000 Unfrozen
Child-SP RetAddr Call Site
00000000`0317f828 00007ffe`71331553 ntdll!ZwWaitForWorkViaWorkerFactory+0x14
00000000`0317f830 00007ffe`6f2b2774 ntdll!TppWorkerThread+0x293
00000000`0317fb40 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`0317fb70 00000000`00000000 ntdll!RtlUserThreadStart+0x21
3 Id: 1c80.85ec Suspend: 1 Teb: 00000000`00b06000 Unfrozen
Child-SP RetAddr Call Site
00000000`0327f508 00007ffe`71331553 ntdll!ZwWaitForWorkViaWorkerFactory+0x14
00000000`0327f510 00007ffe`6f2b2774 ntdll!TppWorkerThread+0x293
00000000`0327f820 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`0327f850 00000000`00000000 ntdll!RtlUserThreadStart+0x21
# 4 Id: 1c80.bf78 Suspend: 1 Teb: 00000000`00b0a000 Unfrozen
Child-SP RetAddr Call Site
00000000`052bfd20 00007ffe`6f2b2774 ttt!ReadRoutine+0xab [c:\users\winne\documents\visual studio 2008\projects\ttt\ttt\main.cpp @ 20]
00000000`052bfdc0 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`052bfdf0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
5 Id: 1c80.1674 Suspend: 1 Teb: 00000000`00b0c000 Unfrozen
Child-SP RetAddr Call Site
00000000`053bf800 00007ff7`160d3126 ttt!std::_Ranit
00000000`053bf830 00007ff7`160d23e7 ttt!std::_Vector_const_iterator
00000000`053bf880 00007ff7`160d1aee ttt!std::_Vector_iterator
00000000`053bf8b0 00007ff7`160d1788 ttt!std::vector
00000000`053bf8f0 00007ffe`6f2b2774 ttt!WriteRoutine+0x38 [c:\users\winne\documents\visual studio 2008\projects\ttt\ttt\main.cpp @ 28]
00000000`053bf980 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`053bf9b0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
其他有用的遍历指令包括:
§ ~*r
显示线程寄存器信息。
0:003> ~*r§ ~*e k;r
此命令意为:在所用线程环境中(~*),分别执行(e)栈指令(k)和寄存器指令(r)。
0:003> ~*e k;r
Child-SP RetAddr Call Site
00000000`00d3f528 00007ffe`6e37dcb0 ntdll!ZwWaitForMultipleObjects+0x14
00000000`00d3f530 00007ffe`6e37dbae KERNELBASE!WaitForMultipleObjectsEx+0xf0
00000000`00d3f830 00007ff7`160d164c KERNELBASE!WaitForMultipleObjects+0xe
00000000`00d3f870 00007ff7`160d65e1 ttt!main+0x11c [c:\users\winne\documents\visual studio 2008\projects\ttt\ttt\main.cpp @ 49]
00000000`00d3f8f0 00007ff7`160d5de2 ttt!WinMain+0xb1 [c:\qt\4.8.4\src\winmain\qtmain_win.cpp @ 131]
00000000`00d3f960 00007ff7`160d5ade ttt!__tmainCRTStartup+0x2f2 [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crtexe.c @ 578]
00000000`00d3fa50 00007ffe`6f2b2774 ttt!WinMainCRTStartup+0xe [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crtexe.c @ 403]
00000000`00d3fa80 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`00d3fab0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
rax=0000000000000214 rbx=0000000000000002 rcx=0000000000000002
rdx=0000000000d3f8a8 rsi=0000000000000000 rdi=0000000000000002
rip=00007ffe71395ef4 rsp=0000000000d3f528 rbp=0000000000000000
r8=0000000000000001 r9=00000000ffffffff r10=0000000000000000
r11=0000000000000244 r12=00000000ffffffff r13=0000000000d3f8a8
r14=0000000000000000 r15=0000000000000001
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!ZwWaitForMultipleObjects+0x14:
00007ffe`71395ef4 c3 ret
Child-SP RetAddr Call Site
00000000`0307fc18 00007ffe`71331553 ntdll!ZwWaitForWorkViaWorkerFactory+0x14
00000000`0307fc20 00007ffe`6f2b2774 ntdll!TppWorkerThread+0x293
00000000`0307ff30 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`0307ff60 00000000`00000000 ntdll!RtlUserThreadStart+0x21
rax=000000000307f790 rbx=0000000002db4e50 rcx=000000000307f7a4
rdx=0000000000000110 rsi=0000000000000010 rdi=0000000002db51d0
rip=00007ffe71398c34 rsp=000000000307fc18 rbp=0000000000000000
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=000000000307f790 r12=0000000000000000 r13=0000000002db31c0
r14=00007ffe71332a50 r15=00007ffe71332ef0
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000244
ntdll!ZwWaitForWorkViaWorkerFactory+0x14:
00007ffe`71398c34 c3 ret
Child-SP RetAddr Call Site
00000000`0317f828 00007ffe`71331553 ntdll!ZwWaitForWorkViaWorkerFactory+0x14
00000000`0317f830 00007ffe`6f2b2774 ntdll!TppWorkerThread+0x293
00000000`0317fb40 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`0317fb70 00000000`00000000 ntdll!RtlUserThreadStart+0x21
rax=0000000070fa5000 rbx=0000000002db5c00 rcx=0000000000000042
rdx=0000000000536e7b rsi=0000000000000010 rdi=0000000002db5f80
rip=00007ffe71398c34 rsp=000000000317f828 rbp=0000000000000000
r8=000000000000058c r9=00000000000015db r10=0000000000000000
r11=0000000070fa4fee r12=0000000000000000 r13=0000000002db31c0
r14=00007ffe71332a50 r15=00007ffe71332ef0
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000244
ntdll!ZwWaitForWorkViaWorkerFactory+0x14:
00007ffe`71398c34 c3 ret
Child-SP RetAddr Call Site
00000000`0327f508 00007ffe`71331553 ntdll!ZwWaitForWorkViaWorkerFactory+0x14
00000000`0327f510 00007ffe`6f2b2774 ntdll!TppWorkerThread+0x293
00000000`0327f820 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`0327f850 00000000`00000000 ntdll!RtlUserThreadStart+0x21
rax=000000000000002d rbx=0000000002db8d20 rcx=000000000327ea50
rdx=00007ffe6d41e9e8 rsi=0000000000000010 rdi=0000000002db90a0
rip=00007ffe71398c34 rsp=000000000327f508 rbp=0000000000000000
r8=0000000000000010 r9=000000000000001e r10=00007ffe71449d80
r11=0000000000000000 r12=0000000000000000 r13=0000000002db31c0
r14=00007ffe71332a50 r15=00007ffe71332ef0
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000244
ntdll!ZwWaitForWorkViaWorkerFactory+0x14:
00007ffe`71398c34 c3 ret
Child-SP RetAddr Call Site
00000000`052bfd20 00007ffe`6f2b2774 ttt!ReadRoutine+0xab [c:\users\winne\documents\visual studio 2008\projects\ttt\ttt\main.cpp @ 20]
00000000`052bfdc0 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`052bfdf0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
rax=0000000000000000 rbx=0000000000000000 rcx=00007ff7160e23b0
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rip=00007ff7160d171b rsp=00000000052bfd20 rbp=0000000000000000
r8=00000000052bfc78 r9=0000000000000000 r10=0000000000000000
r11=0000000000000246 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010204
ttt!ReadRoutine+0xab:
00007ff7`160d171b 8b10 mov edx,dword ptr [rax] ds:00000000`00000000=????????
Child-SP RetAddr Call Site
00000000`053bf800 00007ff7`160d3126 ttt!std::_Ranit
00000000`053bf830 00007ff7`160d23e7 ttt!std::_Vector_const_iterator
00000000`053bf880 00007ff7`160d1aee ttt!std::_Vector_iterator
00000000`053bf8b0 00007ff7`160d1788 ttt!std::vector
00000000`053bf8f0 00007ffe`6f2b2774 ttt!WriteRoutine+0x38 [c:\users\winne\documents\visual studio 2008\projects\ttt\ttt\main.cpp @ 28]
00000000`053bf980 00007ffe`71360d51 kernel32!BaseThreadInitThunk+0x14
00000000`053bf9b0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
rax=0000000004b93810 rbx=0000000000000000 rcx=00000000053bf930
rdx=0000000004b93c10 rsi=0000000000000000 rdi=0000000000000000
rip=00007ff7160d359e rsp=00000000053bf800 rbp=0000000000000000
r8=00007ff7160e23b0 r9=0000000000000003 r10=00007ffe714095d0
r11=0000000000000001 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
ttt!std::_Ranit
00007ff7`160d359e e852dbffff call ttt!ILT+240(??0?$_Iterator_with_baseUrandom_access_iterator_tagstdPEAH_JPEBQEAHAEBQEAHV_Iterator_base (00007ff7`160d10f5)
线程时间
在软件调试的时候,若发现某线程占用执行时间过多,就需要当心是否有问题。线程执行时间的多少,其实就是占用CPU执行工作的时间多少。某线程占用越多,此长彼消,则系统中其它线程占用CPU的时间就越少。
线程的时间信息包括三个方面:自创建之初到现在的总消耗时间、用户模式执行时间、内核模式执行时间。需注意的是,消耗时间一定会远远大于用户时间+内核时间,多出来的是大量空闲时间(为Idle进程占用)。使用下面的命令查看线程时间:
§ .ttime
§ !runaway 7
在!runaway命令中加入标志值7,将显示线程的全部三种时间值。
这两个命令的区别之处是,.ttime只能显示当前线程的时间信息,!runaway能显示当前进程的所有线程时间。下图是这两个命令的使用情况:
0:003> .ttime
Created: Thu Dec 28 16:09:31.131 2017 (UTC + 8:00)
Kernel: 0 days 0:00:00.000
User: 0 days 0:00:00.000
0:003> !runaway 7
User Mode Time
Thread Time
5:1674 0 days 0:00:00.015
4:bf78 0 days 0:00:00.000
3:85ec 0 days 0:00:00.000
2:84f0 0 days 0:00:00.000
1:7274 0 days 0:00:00.000
0:2edc 0 days 0:00:00.000
Kernel Mode Time
Thread Time
0:2edc 0 days 0:00:00.015
5:1674 0 days 0:00:00.000
4:bf78 0 days 0:00:00.000
3:85ec 0 days 0:00:00.000
2:84f0 0 days 0:00:00.000
1:7274 0 days 0:00:00.000
Elapsed Time
Thread Time
0:2edc 0 days 0:00:20.875
1:7274 0 days 0:00:20.868
2:84f0 0 days 0:00:20.868
3:85ec 0 days 0:00:20.868
4:bf78 0 days 0:00:00.037
5:1674 0 days 0:00:00.037