wt(跟踪和监视数据)

在函数调用开始时执行此命令时,wt 命令将运行整个函数,然后显示统计信息。

wt [WatchOptions] [= StartAddress] [EndAddress] 

参数

WatchOptions
指定如何修改显示。 可以使用以下任一选项。

选项 效果

-l 深度

(仅限用户模式)指定要显示的调用的最大深度。 以无提示方式执行至少深度级别高于起点的任何调用。

-m 模块

(仅限用户模式)将显示限制为指定模块内的代码,以及从该模块发出的第一级调用。 可以包含多个 -m 选项来显示来自多个模块的代码,而没有其他模块。

-i 模块

(仅限用户模式)忽略指定模块中的任何代码。 可以包含多个 -i 选项来忽略多个模块中的代码。 如果使用 -m 选项,调试器将忽略所有 -i 选项。

-镍

(仅限用户模式)由于 -m 或 -i 选项,不会显示被忽略的代码中的任何条目。

-数控

不显示单个呼叫信息。

-ns

不显示摘要信息。

-西北

在跟踪期间不显示警告。

-oa

(仅限用户模式)显示呼叫网站的实际地址。

-or

(仅限用户模式)使用默认基数显示所调用函数的返回寄存器值。

-或

(仅限用户模式)在每个返回值的相应类型中显示所调用函数的返回寄存器值。

StartAddress
指定调试器开始执行的地址。 如果不使用 StartAddress,则执行从指令指针指向的指令开始。 有关语法的详细信息,请参阅地址和地址范围语法

EndAddress
指定跟踪结束的地址。 如果不使用 EndAddress,将执行单个指令或函数调用。

环境

模式

用户模式、内核模式

目标

仅限实时调试

平台

用户模式: 所有 内核模式: 仅基于 x86

其他信息

有关发出 wt 命令和相关命令概述的详细信息,请参阅 控制目标

注解

如果想要有关特定函数的行为的信息,但不希望单步执行函数,则 wt 命令非常有用。 而是转到该函数的开头,然后发出 wt 命令。

如果程序计数器位于对应于某个符号(如函数的开头或模块入口点)的点,则 wt 命令将跟踪,直到到达当前返回地址。 如果程序计数器位于调用指令中,则 wt 命令将跟踪,直到它返回到当前位置。 此跟踪在 调试器命令窗口中 进行分析,以及描述命令遇到的各种调用的输出。

如果在函数开头以外的某个位置发出 wt 命令,则命令的行为类似于 p (步骤) 命令。 但是,如果指定 EndAddress,则执行会一直持续到达到该地址,即使此执行涉及许多程序步骤和函数调用。

在源模式下调试时,应仅跟踪到函数正文的左括号的点。 然后,可以使用 wt 命令。 (通常更容易在函数的第一行插入断点,或使用 调试 |运行到 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

  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

在跟踪列表中,第一个数字指定所执行的指令数,第二个数字指定函数的子进程执行的指令数,第三个数字(括号中)指定堆栈中函数的深度(以初始函数为零)。 函数名称的缩进显示调用深度。

在前面的示例中, MyModule!myFunction 在调用多个子例程(包括 printffgets)之前执行 105 个指令,然后在调用这些函数之后执行 54545 个附加指令,但在发出更多调用之前。 但是,在最终计数中,显示 myFunction 执行 112,379 个指令,因为此计数包括 myFunction 及其子级执行的所有指令(myFunction 的子级是直接或间接从 myFunction 调用的函数。

在前面的示例中,另请注意, ILT+1440 (__isatty) 被调用 21 次。 在最终计数中,此函数行为的摘要显示调用的次数、任何单个执行中的最小指令数、任何单个执行中的指令数最大以及每个执行的平均指令数。

如果进行了任何系统调用,它们会显示在计数器中,并在命令输出末尾再次列出。