分类 调试 下的文章

在WinDbg中,可以使用“监视”窗口显示和更改全局和局部变量和寄存器信息。 您可以自定义此窗口以显示您正在跟踪的项。。“监视”窗口可以显示所需的任何变量列表。这些变量可以包括来自任何函数的全局变量和局部变量。任何时候,“监视”窗口都会显示与当前函数范围匹配的变量值。也可以通过“监视”窗口更改这些变量的值。

如何打开监视窗口

  • 通过菜单View--->Watch
  • 快捷键Alt+2
  • 通过工具栏

监视窗口

通过上面的方式打开的窗口如下:

 

 监视窗口可以包含四列。Name列和Value列始终显示,Typecast列和Locations列是可选的。要显示“Typecast”和“Locations”列,请分别单击工具栏上的“类型转换”和“位置”按钮。

在监视窗口中,可以执行以下操作:

  • 若要将变量添加到监视窗口中,选择第一个空单元格名称列中,键入变量名称,然后按 ENTER。 一个带有感叹号变量从单独的模块名称 ()。 如果未指定模块,则使用当前的模块。 若要输入中的地址名称字段中,该地址必须以具有十进制数字 (如有必要,使用该前缀0x)。

    如果您输入的变量名称当前函数的作用域中定义的其值将出现在列。 如果未定义,列将显示"错误:无法获取值"。

    即使未定义变量,它可将其添加到监视窗口。 如果程序计数器输入在其中定义此名称的变量的函数,其值将出现在窗口中在该时间。

  • 要从监视窗口中删除变量,请双击其名称,按 DELETE 键,然后按 ENTER。 通过双击旧名称,键入新名称,然后按 ENTER,也可以使用新名称替换旧名称。

  • 如果变量是一种数据结构,其名称旁边显示复选框。 若要展开和折叠结构成员的显示,请选择或清除该复选框。

  • 类型的整数int显示为十进制值; 类型的整数UINT显示在当前的基数。 若要更改当前的基数,请使用n (设置数量 Base)命令在调试器命令窗口中。

  • 若要更改本地变量的值,请双击其单元格。 输入新值,或编辑旧值。 (剪切、 复制和粘贴命令是可用来进行编辑。)您输入的值可以包含任何C++表达式输入新值或编辑旧值后,您可以按 enter 键来存储新值或按 esc 键放弃它。 如果提交无效的值后按 ENTER,,将重新出现的旧值。

    类型的整数int显示为十进制值; 类型的整数UINT显示在当前的基数。 若要更改当前的基数,请使用n (设置数量 Base)命令在调试器命令窗口中。

  • 类型列 (如果它显示在监视窗口中) 显示每个变量的当前数据类型。 每个变量显示在其自己的数据类型为正确的格式。 数据结构具有其类型名类型列。 其他变量的类型显示在此列中的"输入新的类型"。

    如果您双击"输入新类型",您可以通过输入新的数据类型强制转换类型。 此强制转换更改仅在监视窗口中; 此变量的当前显示它不会更改任何内容在调试器中或在目标计算机上。 此外,如果输入中的新值列中,你输入的文本将分析基于符号的实际类型而不是任何新型中输入类型列。 如果关闭并重新打开监视窗口,您将丢失的数据类型更改。

    您还可以输入中的扩展命令类型列。 调试器会将该符号的地址传递到此扩展插件,并将在一系列的当前行下方的可折叠行中显示生成的输出。 例如,如果在此行中的符号是有效的线程环境块的地址,则可以输入 ! teb类型列来运行! teb此符号的地址上的扩展。

  • 位置列 (如果它显示在监视窗口中) 显示了一种数据结构的每个成员的偏移量。

  • 除了变量之外,还可以监视监视窗口中的以下项:


    • 注册。 当将寄存器添加到监视窗口中时,其名称加上前缀 at 符号 (@)。 与变量不同,不能更改寄存器值通过监视窗口。
    • 包含函数的指针的 Vtable。 当 Vtable 出现在监视窗口中时,您可以浏览表中的函数条目。 如果在指向派生的实现,表示法的基类中包含 Vtable _vtcast_显示来指示要添加的成员由于派生类中。 这些成员展开类似于派生的类类型。
    • 扩展插件的返回值函数,如_EFN_GetPoolData。

与“局部”窗口不同,“监视”窗口不受寄存器上下文更改的影响。在监视窗口中,您只能查看和修改在当前程序计数器范围内定义的变量。如果打开新工作区,监视窗口内容将被丢弃并替换为新工作区中的内容。

五、杂项信息流(MiscInfoStream)

在系统信息流后紧挨着的就是杂项信息流。而系统信息流信息如下

0xEC+0n56=0x124

而杂项信息流如下:

可知偏移是0x124,即证明杂项信息流是紧挨着系统信息流,大小有1364字节。

MiscInfoStream包含各种信息。数据结构如下:

typedef struct_MINIDUMP_MISC_INFO_5 {
ULONG32 SizeOfInfo;
ULONG32 Flags1;
ULONG32 ProcessId;
ULONG32 ProcessCreateTime;
ULONG32 ProcessUserTime;
ULONG32 ProcessKernelTime;
ULONG32 ProcessorMaxMhz;
ULONG32 ProcessorCurrentMhz;
ULONG32 ProcessorMhzLimit;
ULONG32 ProcessorMaxIdleState;
ULONG32 ProcessorCurrentIdleState;
ULONG32 ProcessIntegrityLevel;
ULONG32 ProcessExecuteFlags;
ULONG32 ProtectedProcess;
ULONG32 TimeZoneId;
TIME_ZONE_INFORMATION TimeZone;
WCHAR BuildString[MAX_PATH];
WCHAR DbgBldStr[
40];
XSTATE_CONFIG_FEATURE_MSC_INFO XStateData;
ULONG32 ProcessCookie;
} MINIDUMP_MISC_INFO_5,
*PMINIDUMP_MISC_INFO_5;

typedef
struct_TIME_ZONE_INFORMATION {
LONG Bias;
WCHAR StandardName[
32];
SYSTEMTIME StandardDate;
LONG StandardBias;
WCHAR DaylightName[
32];
SYSTEMTIME DaylightDate;
LONG DaylightBias;
} TIME_ZONE_INFORMATION,
*PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;

typedef
struct_XSTATE_CONFIG_FEATURE_MSC_INFO
{
ULONG32 SizeOfInfo;
ULONG32 ContextSize;
ULONG64 EnabledFeatures;
XSTATE_FEATURE Features[MAXIMUM_XSTATE_FEATURES];
} XSTATE_CONFIG_FEATURE_MSC_INFO,
*PXSTATE_CONFIG_FEATURE_MSC_INFO;

在WinDbg中,可以通过输入命令(u, ub, uu (Unassemble))或使用反汇编窗口查看程序汇编代码。

如何打开 DissAssembly Code窗口

  • 通过菜单View-->Disassembly
  • 快捷键Alt+7
  • 工具栏按钮

DissAssembly窗口

通过上面的方式打开的窗口如下

 

 

调试器获取一段内存,将其解释为二进制机器指令,然后将其反汇编以生成机器指令的汇编语言版本。生成的代码将显示在“反汇编”窗口中。

在“反汇编”窗口中,可以执行以下操作:

  • 若要反汇编内存的不同部分,请在“偏移量”框中键入要反汇编的内存的地址。(键入地址后可以按回车键,但不必如此。)
  • 要查看内存的其他部分,请单击“上一页”或“下一页”按钮,或按“向上翻页”或“向下翻页”键。这些命令分别显示内存前面或后面部分的反汇编代码。通过按右箭头、左箭头、上箭头和下箭头键,可以在窗口内导航。如果使用这些键离开页面,将出现一个新页面。

反汇编窗口中有一个包含两个按钮以及一个具有其他命令的快捷菜单的工具栏。 若要访问菜单,请右键单击标题栏或单击显示的窗口 (在右上角附近的图标显示反汇编窗口工具栏上的快捷菜单按钮的屏幕截图)。 以下列表介绍了一些菜单命令:

  • Go to current address 打开“源”窗口,其中包含与“反汇编”窗口中选定行相对应的源文件,并突出显示该行.

  • Disassemble before current instruction 使当前行放置在“反汇编”窗口的中间。此命令是默认选项。如果清除此命令,当前行将显示在反汇编窗口的顶部,这将节省时间,因为反向反汇编可能会很耗时.

  • Highlight instructions from the current source line 使与当前源代码行对应的所有指令突出显示。通常,一个源代码行将对应于多个汇编指令。如果代码已优化,则这些程序集指令可能不是连续的。此命令使您能够查找从当前源代码行汇编的所有指令.

  • Show source line for each instruction 显示对应于每个汇编指令的源行号.

  • Show source file for each instruction 显示与每个程序指令相对应的源文件名.

四、系统信息流

流目录后面紧接着就是流数据了。第一个流数据就是系统信息流。

可知,这个流的起始于文件偏移0xEC,大小是0x38,也就是56个字节。

从上图可知,系统信息流就是紧挨着流目录尾部。这个流包含了如下操作系统和处理器信息:处理器架构、级别、版本,CPU信息等。数据结构如下:

typedef struct_MINIDUMP_SYSTEM_INFO {
USHORT ProcessorArchitecture;
USHORT ProcessorLevel;
USHORT ProcessorRevision;
union {
USHORT Reserved0;
struct{
UCHAR NumberOfProcessors;
UCHAR ProductType;
};
};
ULONG32 MajorVersion;
ULONG32 MinorVersion;
ULONG32 BuildNumber;
ULONG32 PlatformId;
RVA CSDVersionRva;
union {
ULONG32 Reserved1;
struct{
USHORT SuiteMask;
USHORT Reserved2;
};
};
CPU_INFORMATION Cpu;
} MINIDUMP_SYSTEM_INFO,
*PMINIDUMP_SYSTEM_INFO;

调用堆栈是指向程序计数器当前位置的函数调用链。调用堆栈的顶部函数是当前函数,下一个函数是调用当前函数的函数,依此类推。显示的调用堆栈基于当前程序计数器,除非更改寄存器上下文。

在 WinDbg 中,可以通过输入命令或通过使用Call Stack窗口中查看调用堆栈。

Call Stack窗口的打开方式

  • 通过菜单View--->Call Stack打开
  • 通过快捷键Alt+6打开
  • 通过工具栏按钮打开

Call Stack窗口

作为一种替代方法 k命令时,您可以调用窗口中查看调用堆栈。通过上面的方式打开call stack窗口

call stack窗口中的按钮可用于自定义调用堆栈的视图。要移动到源窗口或反汇编窗口中相应的调用位置,请双击调用堆栈中的一行,或选择一行并按回车键。此操作还将本地上下文更改为选定的堆栈帧。

调用窗口具有一个包含多个按钮和具有带其他命令的快捷菜单的工具栏。 若要访问此菜单中,右键单击标题栏或单击窗口 (在右上角附近的图标显示调用窗口工具栏上的快捷菜单按钮的屏幕截图)。 工具栏和菜单包含以下按钮和命令:

 

  • Raw args 显示传递给函数的前三个参数。在基于x86的处理器上,此显示包括传递给函数的前三个参数(“Args to Child”)。

  • Func info 显示帧指针省略(FPO)数据和其他有关函数的内部信息。此命令仅在基于x86的处理器上可用。

  • Source 在函数名之后显示源模块名和行号(如果调试器具有此信息)。

  • Addrs 显示各种与帧相关的地址。在基于x86的处理器上,此显示包括堆栈帧的基指针(“ChildEBP”)和返回地址(“RetAddr”)。

  • Nonvolatile regs 显示寄存器上下文的非易失性部分。此命令仅在基于安腾的处理器上可用。

  • Frame nums 显示帧编号。帧总是连续编号的,从零开始。

  •  


    Headings 显示列头
  • Arg types 显示有关堆栈中的函数预期和接收的参数的详细信息。

  • Always floating 将使窗口停靠,即使仍拖到停靠位置。

  • Move with frame WinDbg帧移动时使窗口在移动,即使窗口已解除锁定。

其他说明

在用户模式下,堆栈跟踪基于当前线程的堆栈。在内核模式下,堆栈跟踪基于当前寄存器上下文。 可以设置寄存器上下文以匹配特定线程、 上下文记录或捕获帧。 如果Call Stack窗口打开时,使用~1s切换线程、.cxr切换上下文等指令事,Call Stack窗口里显示的堆栈内容会发生改变。