Debugging Tools for Windows |
当从函数调用的开始执行wt 命令时,它会运行整个函数然后显示统计。
选项 | 作用 |
---|---|
-l Depth | (仅用户模式) 指定要显示的调用的最大深度。任何相对于开始位置深度大于Depth 的调用都会在后台执行。 |
-m Module | (仅用户模式) 限制只显示指定模块和模块内的第一级调用。可以包含多个-m选项来显示多个模块的代码而不显示其他任何模块的。 |
-i Module | (仅用户模式) 忽略指定模块中的任何代码。可以包含多个-i来忽略多个模块的代码。如果使用了-m选项,调试器会忽略所有的-i选项。 |
-ni | (用户模式) 不显示所有进入因为-m或-i选项忽略的代码的入口。 |
-nc | 不显示单独的调用信息。 |
-ns | 不显示摘要信息。 |
-nw | 跟踪时不显示警告信息。 |
-oa | (仅用户模式) 显示所有call的地点的实际地址。 |
-or | (仅用户模式) 使用默认基数显示被调用函数的返回寄存器的值。 |
-oR | (仅用户模式) 采用适合各个返回值的类型显示每个被调用函数的返回寄存器的值。 |
模式 | 仅内核模式 |
目标 | 仅活动目标 |
平台 | 用户模式:所有 内核模式:仅x86 |
wt在想查看指定函数的信息而又不想单步通过该函数时很有用。可以到函数的起始地址并执行wt命令。
如果程序计数器正在某个符号对应的位置 (例如某个函数的开始位置或者模块的入口点),wt命令会跟踪进去直到到达当前的返回地址。如果程序计数器在一条call指令上,wt命令跟踪进去直到返回到当前位置。调试器命令窗口中会显示跟踪结果以及对该命令遇到的各种调用的说明。
如果wt命令是从其它地方执行而不是在函数入口,该命令的行为类似p (Step)命令。但是,如果指定了EndAddress,即使包含很多步骤和函数调用,也会一直执行到指定地址。
在源码模式调试时,只有跟踪到看到函数体开始的大括号处。然后可以使用wt命令。(一般在函数的第一行设置一个断点,或者使用Debug | Run to Cursor然后再使用wt命令会比较容易。)
由于wt的输出可能很长,可能希望用日志文件来记录。关于日志文件的更多信息,查看记录日志文件。
下面是一个典型的日志文件的示例。
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
105 0 [ 0] MyModule!myFunction
1 0 [ 1] MyModule!ILT+1555(_printf)
9 0 [ 1] MyModule!printf
1 0 [ 2] MyModule!ILT+370(__stbuf)
11 0 [ 2] MyModule!_stbuf
1 0 [ 3] MyModule!ILT+1440(__isatty)
14 0 [ 3] MyModule!_isatty
50 15 [ 2] MyModule!_stbuf
17 66 [ 1] MyModule!printf
1 0 [ 2] MyModule!ILT+980(__output)
59 0 [ 2] MyModule!_output
39 0 [ 3] MyModule!write_char
111 39 [ 2] MyModule!_output
39 0 [ 3] MyModule!write_char
....
11 0 [ 5] kernel32!__SEH_epilog4
54 11675 [ 4] kernel32!ReadFile
165 11729 [ 3] MyModule!_read
100 11895 [ 2] MyModule!_filbuf
91 11996 [ 1] MyModule!fgets
54545 83789 [ 0] MyModule!myFunction
1 0 [ 1] MyModule!ILT+1265(__RTC_CheckEsp)
2 0 [ 1] MyModule!_RTC_CheckEsp
54547 83782 [ 0] MyModule!myFunction
112379 instructions were executed in 112378 events (0 from other threads)
Function Name Invocations MinInst MaxInst AvgInst
MyModule!ILT+1265(__RTC_CheckEsp) 1 1 1 1
MyModule!ILT+1440(__isatty) 21 1 1 1
MyModule!ILT+1540(__ftbuf) 21 1 1 1
....
ntdll!memcpy 24 1 40 19
ntdll!memset 2 29 29 29
23 system calls were executed
Calls System Call
23 ntdll!KiFastSystemCall
在跟踪的清单中,第一个数字表示执行的指令条数,第二个数字表示调用堆栈中函数的深度 (初始函数深度为0)。 函数名的缩进表明了调用深度。
前面的例子中, MyModule!myFunction 在调用anotherFunction 之前执行了141条指令,而在anotherFunction 返回后又执行了4条。但是,在最终记数中 显示myFunction 执行了213条指令,因为包含了myFunction 和它的子函数执行的所有指令。(myFunction的子函数指从myFunction 调用到的函数,包括直接和非直接的。)
这个例子中,也要注意deeperFunction 被调用了两次。最后的记数中,该函数行为的摘要表明了它被调用的次数、单次调用执行的最小指令条数、单次调用执行的最大指令条数和每次调用执行的指令的平均条数。
如果进行了任何系统调用,它们会在计数中出现并且在命令末尾列出。
关于使用wt命令的更多信息和其他相关命令的概述,查看控制调试目标。