更改上下文

在内核模式调试中,有许多进程、线程,有时还有用户会话同时执行。 因此,诸如“虚拟地址 0x80002000”或“ eax 寄存器”之类的短语是不明确的。 必须指定能够理解此类短语的上下文

调试器有五种不同的上下文,可以在调试时进行设置:

  1. 会话上下文指示默认用户会话。

  2. 进程上下文决定调试器如何解释虚拟地址。

  3. 用户模式地址上下文几乎从不直接设置。 更改进程上下文时,会自动设置此上下文。

  4. 寄存器上下文决定调试器如何解释寄存器,并控制堆栈跟踪的结果。 此上下文也称为线程上下文,但该术语并不完全准确。 显式上下文也是寄存器上下文的类型。 如果指定显式上下文,则使用该上下文而不是当前寄存器上下文。

  5. 本地上下文确定调试器如何解释局部变量。 此上下文也称为作用域

会话上下文

多个登录会话可以同时运行。 每个登录会话都有自己的进程。

!session 扩展插件显示所有登录会话或更改当前会话上下文。

会话上下文由 !sprocess!spoolused 扩展在会话编号输入为“-2”时使用。

当会话上下文发生更改时,进程上下文会自动更改为该会话的活动进程。

进程上下文

每个进程都有自己的页面目录,用于记录虚拟地址映射到物理地址的方式。 当进程中的任何线程正在执行时,Windows 操作系统使用此页目录来解释虚拟地址。

在用户模式调试期间,当前进程确定进程上下文。 调试器命令、扩展和调试信息窗口中使用的虚拟地址是通过使用当前进程的页面目录来解释。

在内核模式调试期间,可以使用 .process(设置进程上下文)命令设置进程上下文。 使用此命令可以选择用于解释虚拟地址的进程的页面目录。 设置进程上下文后,可以在任何获取地址的命令中使用此上下文。 甚至可以在此地址处设置断点。 通过在 .process 命令中包含 /i 选项以指定侵入调试,还可以使用内核调试器在用户空间中设置断点。

还可以通过在内核空间函数上使用进程特定的断点,从内核调试器设置用户模式断点。 设置战略性断点,等待合适的上下文出现。

用户模式地址上下文是进程上下文的一部分。 通常,无需直接设置用户模式地址上下文。 如果设置进程上下文,则用户模式地址上下文会自动更改为进程的相关页表的目录基。

当在内核模式调试期间设置进程上下文时,该进程上下文将被保留,直到另一个 .process 命令更改上下文。 在 .process.context 命令更改之前,用户模式地址上下文也会保留。 当目标计算机执行时,这些上下文不会更改,也不受寄存器上下文或本地上下文更改的影响。

寄存器上下文

每个线程都有自己的寄存器值。 当一个线程正在执行时,这些值被存储在 CPU 寄存器中;而当另一个线程正在执行时,它们被存储在存储器中。

在用户模式调试期间,当前线程通常确定寄存器上下文。 调试器命令、扩展和调试信息窗口中对寄存器的任何引用都将根据当前线程的寄存器进行解释。

在执行用户模式调试时,可以使用以下命令之一将寄存器上下文更改为当前线程以外的值:

.cxr(显示上下文记录)

.ecxr(显示异常上下文记录)

在内核模式调试期间,可以使用各种调试器命令控制寄存器上下文,包括以下命令:

.thread(设置寄存器上下文)

.cxr(显示上下文记录)

.trap(显示陷阱帧)

这些命令不会更改 CPU 寄存器的值。 相反,调试器从内存中的位置检索指定的寄存器上下文。 实际上,调试器只能检索保存的寄存器值。 (其他值动态设置,不会保存。 保存的值足以重新创建堆栈跟踪。

设置寄存器上下文后,新寄存器上下文将用于使用寄存器值的任何命令,例如 k(显示堆栈回溯)r(寄存器)

但是,在调试多处理器计算机时,某些命令允许指定处理器。 (有关此类命令的详细信息,请参阅 多处理器语法。)如果为命令指定处理器,则即使指定的处理器是当前活动的处理器,该命令也会使用指定处理器上活动线程的寄存器上下文,而不是当前寄存器上下文。

此外,如果寄存器上下文与当前处理器模式设置不匹配,则这些命令会产生不正确的或毫无意义的输出。 为了避免输出错误,依赖于寄存器状态的命令会失败,直到更改处理器模式以匹配寄存器上下文。 若要更改处理器模式,请使用 .effmach (Effective Machine) 命令,

更改寄存器上下文还会更改本地上下文。 通过这种方式,寄存器上下文可能会影响局部变量的显示。

如果发生任何应用程序执行、单步执行或跟踪,则会立即重置寄存器上下文以匹配程序计数器的位置。 在用户模式下,如果当前进程或线程发生更改,则寄存器上下文也会重置。

寄存器上下文会影响堆栈跟踪,因为堆栈跟踪从堆栈指针寄存器(x86 处理器上的 esp)指向的位置开始。 如果寄存器上下文设置为无效或不可访问的值,则无法获取堆栈跟踪。

可以使用 .apply_dbp(将数据断点应用到上下文)命令,将处理器断点(数据断点)应用到特定的寄存器上下文。

本地上下文

当程序运行时,局部变量的含义取决于程序计数器的位置,因为此类变量的范围仅扩展到定义它们的函数。

执行用户模式或内核模式调试时,调试器使用当前函数的作用域(堆栈上的当前帧)作为本地上下文。 若要更改此上下文,请使用 .frame(设置本地上下文)命令,或在“调用”窗口中双击所需的帧。

在用户模式调试中,本地上下文始终是当前线程堆栈跟踪中的帧。 在内核模式调试中,本地上下文始终是当前寄存器上下文线程的堆栈跟踪中的一个帧。

对于本地上下文,一次只能使用一个堆栈帧。 无法访问其他帧中的局部变量。

如果发生以下任何事件,则会重置本地上下文:

  • 任何程序执行、单步执行或跟踪

  • 在任何命令中使用线程分隔符 (~)

  • 对寄存器上下文的任何更改

!for_each_frame 扩展使你能够重复执行单个命令,对堆栈中的每一帧执行一次。 此命令更改每个帧的本地上下文,执行指定的命令,然后将本地上下文返回到其原始值。