调试笔记之Check Build
这两天使用Virtual PC(2004)安装了Windows XP SP3的Check版本。有些要点值得分享和备忘。
1 安装过程中的蓝屏
在安装程序复制好文件,重新启动时,会出现蓝屏,蓝屏代码是未处理的内核态异常,异常代码是80000003,即断点异常。看到这个蓝屏后,我想到是Check版本中的某些ASSERT所导致的,保留了更多的断言是Check版本的最大特色。对于断言,如果有调试器,那么系统就会中断到调试器,然后继续也可以了。
但是此时还不能进入系统启用调试选项,怎么办呢?于是想到了按F5在高级启动选项中选择调试选项。关于这个默认调试选项采用的连接参数,一种说法是COM1,一种说法是可以枚举到的最大编号COM口。实验下来,是第二种。也就是当调试器中使用COM2时,成功与虚拟机中的KD建立了连接。这验证了《软件调试》所采信的说法(18.3.3,P478)对于XP SP3也是正确的。
以下是初始的输出信息:
Opened \\.\pipe\com2
Waiting to reconnect...
Break repeatedly, break Once, Ignore, terminate Process, or terminate Thread (boipt)?
这是ASSERT断言所导致的询问,可以输入boipt四个字符之一来选择动作。先输入b让其反复中断。
下面一行的提示信息告诉我们如何把上下文切换到ASSERT断言时所保存下来的上下文:
Execute '.cxr F8999E90' to dump context
而后,WinDBG开始与KD通话,获取对方的详细信息:
Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
Kernel Debugger connection established.
WARNING: Inaccessible path: 'D:\new\SYMBOLS.PRI\retail'
Symbol search path is: SRV*d:\symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
此时按Ctrl+Alt+V让WinDBG输出尽可能多的信息:
Verbose mode ON.
下面两句是收到关于内核模块的符号加载事件:
ntoskrnl.exe
ModLoad: 80a02000 80d8e000 ntoskrnl.exe
接下来,WinDBG开始与KD通话,获取对方的详细信息:
Windows XP Kernel Version 2600 (Service Pack 3) MP (1 procs) Checked x86 compatible
Built by: 2600.xpsp.080413-2133
Kernel base = 0x80a02000 PsLoadedModuleList = 0x80af5708
Debug session time: Thu Sep 11 05:11:57.870 2008 (GMT+8)
System Uptime: 0 days 0:00:16.043
了解了调试目标的基本信息后,WinDBG为其选择匹配的工作空间,并根据工作空间的参数,加载其中定义的扩展模块:
Loaded dbghelp extension DLL
Loaded ext extension DLL
Loaded exts extension DLL
Loaded kext extension DLL
Loaded kdexts extension DLL
最后,WinDBG准备进入了命令模式,显示异常信息和有关的指令:
Break instruction exception - code 80000003 (first chance)
nt!DbgBreakPoint:
80ab8f5c cc int 3
因为我们刚才选择的是反复中断,所以可以输入g命令,恢复执行,而后会再次中断:
kd> g
*** Assertion failed: The system BIOS on this machine does not properly
support the processor. The system BIOS did not load any microcode update.
A BIOS containing the latest microcode update is needed for system reliability.
(CurrentUpdateRevision != 0 || ProcessorSignature.u.hw.Family < 6)
*** Source File: d:\xpsp\drivers\filters\update\update.c, line 1116
Break repeatedly, break Once, Ignore, terminate Process, or terminate Thread (boipt)?
这次我们看到了失败断言的详细信息:
1)这个断言位于update.c的1116行,源程序的完整路径是d:\xpsp\drivers\filters\update\update.c
2)断言的提示信息告诉我们“这台机器”的BIOS没有很好的支持处理器。因为它没有加载任何微指令更新。 我在刷CPU一文中曾经提到过,今天的主流x86 CPU都是可以更新伪代码的。为了保证安全,所以其更新过程是很严格的,需要BIOS配合。因此这个断言是抱怨BIOS缺少这个支持。因为我们用的是虚拟机,其BIOS是模拟出的,因此出这问题,情有可原。
观察栈回溯,可以看到IO管理器加载负责更新伪指令的Update驱动的过程:
kd> k
ChildEBP RetAddr
f8999e70 80abac1e nt!DbgBreakPoint
f899a160 80abac60 nt!RtlAssert2+0x104
f899a17c f7fd3327 nt!RtlAssert+0x18
f899a5fc f7fd5805 Update!UpdateLoadUpdateOnDevice+0x2ab
f899aa20 80a21c17 Update!UpdatePnPDispatch+0xfd
f899aa38 80b4f526 nt!IopfCallDriver+0x51
f899aa64 80b4f66e nt!IopSynchronousCall+0xf0
f899aaac 80a2c099 nt!IopStartDevice+0x82
f899aac8 80b4e2e8 nt!PipProcessStartPhase1+0x9f
f899ad24 80b4ebe4 nt!PipProcessDevNodeTree+0x238
f899ad58 80a2d029 nt!PiProcessStartSystemDevices+0x70
f899ad80 80aca927 nt!PipDeviceActionWorker+0x187
f899adac 80bc7608 nt!ExpWorkerThread+0x10f
f899addc 80ad99a2 nt!PspSystemThreadStartup+0x34
00000000 00000000 nt!KiThreadStartup+0x16
下面是update驱动的详细信息:
kd> lmvm update*
start end module name
f7fd2000 f8032100 Update (pdb symbols) d:\symbols\update.pdb\A3B3FEB7251945FCB2A10FB50CC19BE71\update.pdb
Loaded symbol image file: Update.SYS
Image path: \SystemRoot\System32\Drivers\Update.SYS
Image name: Update.SYS
Timestamp: Mon Apr 14 05:52:51 2008 (4802B8F3)
CheckSum: 0006781B
ImageSize: 00060100
Translations: 0000.04b0 0000.04e0 0409.04b0 0409.04e0
最后输入i,胡略这个断言,那么系统就可以继续向前运行了。
2 OOBE
OOBE是Out Of Box Experience的缩写,指代用户第一次进入系统时的“体验”。下图显示了XP的OOBE界面:
那么这个OOBE界面是哪个程序现实的呢?答案是msoobe.exe,位于c:\windows\system32\oobe目录是,事实上,OOBE过后,这个程序还在,不过再运行它,它便会自动退出。
3 HTTP输出的配置信息
输出更多的调试信息是Check版本的另一大特色,例如,下面是HTTP.sys输出的配置信息:
Http.sys Configuration:
g_UlDebug = 0x0000000000000000
g_UlBreakOnError = 0
g_UlVerboseErrors = 0
g_UlComputerName = ADVDBG-PC
g_UlIdleConnectionsHighMark = 0
g_UlIdleConnectionsLowMark = 0
g_UlIdleListTrimmerPeriod = 30
g_UlMaxEndpoints = 0
g_UlOptForIntrMod = 0
g_UlEnableNagling = 0
g_UlEnableThreadAffinity = 0
g_UlThreadAffinityMask = 0x1
g_UlMaxCopyThreshold = 2048
g_UlMaxBufferedSends = 4
g_UlMaxBytesPerSend = 65536
g_UlMinBytesPerSend = 4096
g_UlPipelineThreshold = 3
g_UlConnectionSendLimit = 131072
g_UlGlobalSendLimit = 0
g_UlOpaqueIdTableSize = 1024
g_UlMaxRequestBytes = 16384
g_UlReceiveBufferSize = 8176
g_UlResponseBufferSize = 0
g_UlMaxFieldLength = 16384
g_MaxConnections = 0xffffffff
g_UlDisableLogBuffering = 0
g_UlLogBufferSize = 0
CodePage = 1252
EnableNonUtf8 = 1
FavorUtf8 = 1
EnableDbcs = 0
PercentUAllowed = 1
AllowRestrictedChars = 0
HostnameDecodeOrder = 0x1b
AbsPathDecodeOrder = 0x7
UrlSegmentMaxLength = 260
UrlSegmentMaxCount = 255
g_UlMaxInternalUrlLength = 256
g_UlMaxZombieHttpConnCount = 128
g_UlDisableServerHeader = 0
g_UlAllowCaseInSensitiveVerbs= 0
g_UlAllowWeakHeaderNameSyntax= 0
ErrorLogging = 1
Fields Picked = 0x7c884c7
Fields Default = 0x7c884c7
Fields All = 0x7dff4e7
ThreadsPerCpu = 1
IrpContextLookasideDepth = 64
ReceiveBufferLookasideDepth = 64
ResourceLookasideDepth = 32
RequestBufferLookasideDepth = 64
IntlRequestLookasideDepth = 64
ResponseBufferLookasideDepth = 64
SendTrackerLookasideDepth = 64
LogFileBufferLookasideDepth = 16
LogDataBufferLookasideDepth = 64
WriteTrackerLookasideDepth = 64
EnableCache = 1
MaxCacheUriCount = 0
MaxCacheMegabyteCount = 0
ScavengerPeriod = 120
HashTableBits = -1
MaxUriBytes = 262144
ScavengerTrimMB = 0
4 Hibernate输出的统计信息
当系统进入休眠时输出的信息简单明了,言简意赅,值得学习:
HIBER: 14896 Pages written in 2799 Dumps (3 runs).
HIBER: 38389 Pages processed (38 % compression)
HIBER: Elapsed time 13.969 seconds
HIBER: I/O time 8.766 seconds (62%) 0 MB/sec
HIBER: Init time 0.011 seconds ( 0%)
HIBER: Copy time 0.561 seconds ( 4%) 220734016 Bytes
5 调试ACPI
ACPI调试需要Check版本的ACPI驱动,如果要调试的目标系统是Free版本,那么就需要替换ACPI.SYS文件,在XP和Vista这样对系统文件有特别保护的系统上做这件事不能算太麻烦,但是毕竟有些罗嗦。而如果目标系统是Check版本,那么就没这个麻烦了,可以直接开始ACPI调试了。
键入下面的命令后:
!amli debugger
下次再有人执行ACPI脚本时就会中断下来,可以与AMLI调试器对话了。