cc682/NetRoc
http://netroc682.spaces.live.com/
vercommand (Show Debugger Command Line)
vercommand 命令显示打开调试器时使用的命令行。
语法
vercommand
环境
模式
|
用户模式、内核模式
|
目标
|
活动目标、崩溃转储
|
平台
|
所有
|
version (Show Debugger Version)
version 命令显示调试器和所有已加载的扩展DLL的版本信息。该命令也会显示目标机的操作系统版本。
不要将该命令和!version (Show DLL Version)扩展命令混淆。
语法
version
环境
模式
|
用户模式、内核模式
|
目标
|
活动目标、崩溃转储
|
平台
|
所有
|
参见
CTRL+W (Show Debugger Version)、vertarget (Show Target Computer Version)
vertarget (Show Target Computer Version)
vertarget 命令显示目标机的Microsoft Windows操作系统版本。
语法
vertarget
环境
模式
|
用户模式、内核模式
|
目标
|
活动目标、崩溃转储
|
平台
|
所有
|
参见
CTRL+W (Show Debugger Version)、version (Show Debugger Version)
wrmsr (Write MSR)
wrmsr 命令向指定地址的模式相关寄存器(Model-Specific Register (MSR))写入一个值。
语法
wrmsr Address Value
参数
Address
指定MSR的地址。
Value
指定要写入MSR的64位16进制值。
环境
注释
wrmsr 命令可以显示x86、Itanium、x64平台的MSR。MSR的定义是平台相关的。
参见
rdmsr (Read MSR)
wt (Trace and Watch Data)
当从函数调用的开始执行wt 命令时,它会运行整个函数然后显示统计。
语法
wt [WatchOptions] [= StartAddress] [EndAddress]
参数
WatchOptions
指定如何改变显示。可以使用下面这些选项。
选项
|
作用
|
-l Depth
|
(仅用户模式) 指定要显示的调用的最大深度。任何相对于开始位置深度大于Depth 的调用都会在后台执行。
|
-m Module
|
(仅用户模式) 限制只显示指定模块和模块内的第一级调用。可以包含多个-m选项来显示多个模块的代码而不显示其他任何模块的。
|
-i Module
|
(仅用户模式) 忽略指定模块中的任何代码。可以包含多个-i来忽略多个模块的代码。如果使用了-m选项,调试器会忽略所有的-i选项。
|
-ni
|
(用户模式) 不显示所有进入因为-m或-i选项忽略的代码的入口。
|
-nc
|
不显示单独的调用信息。
|
-ns
|
不显示摘要信息。
|
-nw
|
跟踪时不显示警告信息。
|
-oa
|
(仅用户模式) 显示所有call的地点的实际地址。
|
-or
|
(仅用户模式) 使用默认基数显示被调用函数的返回寄存器的值。
|
-oR
|
(仅用户模式) 采用适合各个返回值的类型显示每个被调用函数的返回寄存器的值。
|
StartAddress
指定调试器开始执行的地址。如果不使用StartAddress,执行从指令指针指向的位置开始。该语法的更多信息,查看地址和地址区域语法。
EndAddress
指定跟踪结束的地址。如果不使用EndAddress,则执行单条指令或函数调用。
环境
模式
|
仅内核模式
|
目标
|
仅活动目标
|
平台
|
用户模式:所有 内核模式:仅x86
|
注释
wt在想查看指定函数的信息而又不想单步通过该函数时很有用。可以到函数的起始地址并执行wt命令。
如果程序计数器正在某个符号对应的位置 (例如某个函数的开始位置或者模块的入口点),wt命令会跟踪进去直到到达当前的返回地址。如果程序计数器在一条call指令上,wt命令跟踪进去直到返回到当前位置。调试器命令窗口中会显示跟踪结果以及对该命令遇到的各种调用的说明。
如果wt命令是从其它地方执行而不是在函数入口,该命令的行为类似p (Step) 命令。但是,如果指定了EndAddress,即使包含很多步骤和函数调用,也会一直执行到指定地址。
在源码模式调试时,只有跟踪到看到函数体开始的大括号处。然后可以使用wt命令。(一般在函数的第一行设置一个断点,或者使用Debug | Run to Cursor然后再使用wt命令会比较容易。)
由于wt的输出可能很长,可能希望用日志文件来记录。关于日志文件的更多信息,查看记录日志文件。
下面是一个典型的日志文件的示例。
0:000> l+ Source options set to show source lines
Source options are f:
1/t - Step/trace by source line
2/l - List source line for LN and prompt
4/s - List source code at prompt
8/o - Only show source code at prompt
0:000> p Not yet at the function call: use "p"
> 44: minorVariableOne = 12;
0:000> p
> 45: variableOne = myFunction(2, minorVariable);
0:000> t At the function call: now use "t"
MyModule!ILT+10(_myFunction):
0040100f e9cce60000 jmp MyModule!myFunction (0040f6e0)
0:000> t
> 231: {
0:000> wt At the function beginning: now use "wt"
Tracing MyModule!myFunction to return address 00401137
141 [ 0] MyModule!myFunction
20 [ 1] MyModule!anotherFunction
5 [ 2] MyModule!deeperFunction
10 [ 1] MyModule!anotherFunction
3 [ 2] MyModule!deeperFunction
30 [ 1] MyModule!anotherFunction
4 [ 0] MyModule!myFunction
147 Instructions were executed 146(0 from other threads) traces 147 sums
Function Name Invocations MinInstr MaxInstr AvgInstr
MyModule!deeperFunction 2 3 5 4
MyModule!anotherFunction 1 68 68 68
MyModule!myFunction 1 213 213 213
0 system calls were executed
System Call:
在跟踪的清单中,第一个数字表示执行的指令条数,第二个数字表示调用堆栈中函数的深度 (初始函数深度为0)。 函数名的缩进表明了调用深度。
前面的例子中, MyModule!myFunction 在调用anotherFunction 之前执行了141条指令,而在anotherFunction 返回后又执行了4条。但是,在最终记数中 显示myFunction 执行了213条指令,因为包含了myFunction 和它的子函数执行的所有指令。(myFunction的子函数指从myFunction 调用到的函数,包括直接和非直接的。)
这个例子中,也要注意deeperFunction 被调用了两次。最后的记数中,该函数行为的摘要表明了它被调用的次数、单次调用执行的最小指令条数、单次调用执行的最大指令条数和每次调用执行的指令的平均条数。
如果进行了任何系统调用,它们会在计数中出现并且在命令末尾列出。
该例子是从用户模式调试中获得的。在内核模式下,显示有一些不同。函数调用有两列数据:
· 第一列表示在函数名那一行执行的指令条数。
· 第二列表示该函数所有子函数执行的指令数量。
附加信息
关于使用wt命令的更多信息和其他相关命令的概述,查看控制调试目标。
x (Examine Symbols)
x命令显示所有上下文中匹配指定模板的符号。
语法
x [Options] Module!Symbol
x [Options] *
参数
Options
指定符号搜索选项。可以使用下面这些选项的一个或者多个:
/t
如果知道数据类型的话,显示每个符号的数据类型。
/v
显示每个符号的符号类型(局部、全局、参数或未知) 。该选项还显示每个符号的大小。函数符号的大小是该函数在内存中的大小。其他符号的大小是该符号对应的数据类型的大小。该大小总是以字节为单位并且以16进制形式显示。
/s Size
仅显示以字节为单位的大小等于Size的符号。函数符号的大小是该函数在内存中的大小。其他符号的大小是该符号对应的数据类型的大小。未知大小的符号总是被显示出来。Size不能为0。
/q
以引用的形式显示符号名。
/p
显示函数名喝它的参数时省略左括号前的空格。这种类型的输出使得将x的显示复制到其他地方时更容易。
/f
显示函数的数据大小。
/d
显示数据的数据大小。
/a
按照地址以升序的形式排序输出。
/A
按照地址以降序的形式排序输出。
/n
按照名字以升序的形式排序输出。
/N
按照名字以降序的形式排序输出。
/z
按照大小以升序的形式排序输出。
/Z
按照大小以降序的形式排序输出。
Module
指定要搜索的模块。该模块可以是.exe、 .dll、.sys 文件。 Module 可以包含各种通配符和修饰符。该语法的更多信息,查看字符串通配符语法。
Symbol
指定符号必须包含的模板。Symbol可以包含各种通配符和修饰符。该语法的更多信息,查看字符串通配符语法。
由于该模板用来匹配符号,这种匹配是不区分大小写的,并且开头的下划线(_) 相当于任意多个下划线。在Symbol中可以加入空格,所以可以不通过通配符来指定包含空格的符号名 (例如 "operator new" 或"Template<A, B>")。
环境
模式
|
用户模式、内核模式
|
目标
|
活动目标、崩溃转储
|
平台
|
所有
|
注释
X命令显示指定模块(Module)的公有符号中匹配指定模板(Symbol)的项。例如,下面的命令查找MyModule 中所有包含字符串"spin"的符号。
0:000> x mymodule!*spin*
下面的命令在MyModule 中快速定位"DownloadMinor" 和"DownloadMajor"符号。
0:000> x mymodule!downloadm??or
也可以使用下面的命令显示MyModule 中所有符号。
0:000> x mymodule!*
前一个命令也会强制调试器重新加载MyModule 的符号信息。如果要重新加载该模块得符号但是不显示那么多信息,可以使用下面的命令。
0:000> x mymodule!*start*
包含"start"的符号较少。因此,上面的命令会显示一些表明命令运行的输出,但是避免了像x mymodule!*一样很长的输出。
显示中包含每个符号的起始地址和完整的符号名。如果符号是一个函数名,还会包含参数类型的列表。如果符号是全局变量,则还会显示它的当前值。
这是另一个x命令的特殊用法。用来显示当前上下文所有局部变量的地址和名字。
0:000> x *
注意 大多数情况下如果没有加载私有符号,则不能访问局部变量。关于这种情况的更多信息,查看dbgerr005: Private Symbols Required。要显示局部变量的值,使用dv (Display Local Variables)命令。
下面的示例说明附加的x选项。使用/v选项时,输出的第一列显示符号类型 (local、 global、 parameter、 function或unknown)。第二列是符号地址。第三列是符号大小,以字节为单位。第四列是模块名和符号名。某些情况下,输出后面跟了一个等号 (=)和符号的数据类型。符号的来源 (公有的或实际的符号信息)也会显示出来。
kd> x /v nt!CmType*
global 806c9e68 0 nt!CmTypeName = struct _UNICODE_STRING []
global 806c9e68 150 nt!CmTypeName = struct _UNICODE_STRING [42]
global 806c9e68 0 nt!CmTypeName = struct _UNICODE_STRING []
global 805bd7b0 0 nt!CmTypeString = unsigned short *[]
global 805bd7b0 a8 nt!CmTypeString = unsigned short *[42]
上例中,是以16进制给出大小,而数据类型是以10进制形式。因此,上例的最后一行中,数据类型是42个unsigned short整数的数组。数组大小是42*4 = 168,而168的16进制是0xA8。
可以使用/s Size选项来显示大小的字节数为指定值的符号。例如,可以限制上面的命令只显示相应对象的大小为0xA8的符号。
kd> x /v /s a8 nt!CmType*
global 805bd7b0 a8 nt!CmTypeString = unsigned short *[42]
/t选项使得调试器显示每个符号数据类型的信息。注意对于很多符号,该信息没有/t选项也会显示出来。使用/t时,这些符号的符号信息会被显示两次。
0:001> x prymes!__n*
00427d84 myModule!__nullstring = 0x00425de8 "(null)"
0042a3c0 myModule!_nstream = 512
Type information missing error for _nh_malloc
004021c1 myModule!MyStructInstance = struct MyStruct
00427d14 myModule!_NLG_Destination = <no type information>
0:001> x /t prymes!__n*
00427d84 char * myModule!__nullstring = 0x00425de8 "(null)"
0042a3c0 int myModule!_nstream = 512
Type information missing error for _nh_malloc
004021c1 struct MyStruct myModule!MyStructInstance = struct MyStruct
00427d14 <NoType> myModule!_NLG_Destination = <no type information>
下面的例子说命令过滤模块notepat.exe中的函数时对/f开关的使用。
0:000> x /f /v notepad!*main*
prv func 00000001`00003340 249 notepad!WinMain (struct HINSTANCE__ *, struct HINSTANCE__ *, char *, int)
prv func 00000001`0000a7b0 1c notepad!WinMainCRTStartup$filt$0 (void)
prv func 00000001`0000a540 268 notepad!WinMainCRTStartup (void)
参见
Verifying Symbols、dv (Display Local Variables)
z (Execute While)
z 命令当给定条件为真时条件执行一条命令。
语法
用户模式
Command ; z( Expression )
内核模式
Command ; [Processor] z( Expression )
参数
Command
指定当Expression 的值为非0时要执行的命令。该命令总是至少会被执行一次。
Processor
指定要应用该条件测试的处理器。该语法的更多信息,查看多处理器语法。只有内核模式下可以制定处理器。
Expression
指定要测试的条件。如果该条件是非0值,Command 命令会再一次执行并且再次测试Expression 的值。该语法的更多信息,查看数值表达式语法。
环境
模式
|
用户模式、内核模式
|
目标
|
活动目标、崩溃转储
|
平台
|
所有
|
注释
在很多调试器命令中,分号用来分隔多个不相关的命令。但是,在z命令中,分号用来将"z"和Command 参数分开。
Command 命令总是至少执行一次,然后测试Expression 。如果条件为非0值,该命令再次执行,并且再次测试Expression 。(这个特性和C语言的do - while 循环相似,而不像while 循环。)
如果"z"左边有多个分号,当Expression 条件为真时"z"左边的所有命令都会被执行。它们可以是任何允许用分号结尾的调试器命令。
如果在z命令之后还添加了另外的分号和命令,这些命令在循环完成之后执行。一般不建议使用以"z"开头的行,某些其它动作,这样会产生奇怪的输出。注意z命令可以嵌套。
要中断太长的循环,可以在CDB或KD中使用CTRL+C或者在WinDbg中使用Debug | Break 或CTRL+BREAK。
下面是一个使用不必要的复杂方式来清空eax寄存器的示例。
0:000> reax = eax - 1 ; z(eax)
下面的命令将eax和ebx加1,直到它们中的一个大于8,然后将ecx递增一次。
0:000> reax=eax+1; rebx=ebx+1; z((eax<8)|(ebx<8)); recx=ecx+1
下面的命令使用C++ 表达式语法并将伪寄存器$t0作为循环变量。
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
0:000> db pindexcreate[@$t0].szKey; r$t0=@t0+1; z( @$t0 < cIndexCreate )
参见
j (Execute If-Else)