更改上下文
在内核模式调试中,有许多进程、线程,有时用户会话同时执行。 Therfore,例如“虚拟地址0x80002000”或“ eax register”等短语是歧义的。 必须指定可以理解此类短语的 上下文 。
调试器在调试时可以设置五个不同的上下文:
会话上下文指示默认用户会话。
进程上下文确定调试器如何解释虚拟地址。
用户模式地址上下文几乎永远不会直接设置。 更改进程上下文时,会自动设置此上下文。
寄存器上下文确定调试器如何解释寄存器,并控制堆栈跟踪的结果。 此上下文也称为 线程上下文,但该术语并不完全准确。 显式上下文也是一种寄存器上下文。 如果指定显式上下文,则使用该上下文而不是当前寄存器上下文。
本地上下文确定调试器如何解释局部变量。 此上下文也称为 范围。
会话上下文
多个登录会话可以同时运行。 每个登录会话都有自己的进程。
!session 扩展显示所有登录会话或更改当前会话上下文。
会话上下文由 !sprocess 和 !spoolused 扩展在输入为“-2”时使用。
更改会话上下文后,进程上下文会自动更改为该会话的活动进程。
进程上下文
每个进程都有自己的页面目录,用于记录虚拟地址如何映射到物理地址。 当进程内的任何线程正在执行时,Windows 操作系统使用此页目录来解释虚拟地址。
在用户模式调试期间,当前进程确定进程上下文。 使用当前进程的页目录解释调试器命令、扩展和调试信息窗口中使用的虚拟地址。
在内核模式调试期间,可以使用 .process (Set Process Context) 命令来设置进程上下文。 使用此命令选择哪个进程的页面目录用于解释虚拟地址。 设置进程上下文后,可以在采用地址的任何命令中使用此上下文。 甚至可以在此地址设置断点。 通过在 .process 命令中包含 /i 选项来指定入侵调试,还可以使用内核调试器在用户空间中设置断点。
还可以通过在内核空间函数上使用特定于进程的断点从内核调试器设置用户模式断点。 设置战略断点并等待相应的上下文出现。
用户模式地址上下文是进程上下文的一部分。 通常,无需直接设置用户模式地址上下文。 如果设置进程上下文,则用户模式地址上下文会自动更改为进程相关页表的目录基。
在内核模式调试期间设置进程上下文时,该进程上下文将保留,直到另一个 .process 命令更改上下文。 在 .process 或 .context 命令更改之前,用户模式地址上下文也会保留。 目标计算机执行时不会更改这些上下文,并且它们不受注册上下文或本地上下文更改的影响。
注册上下文
每个线程都有自己的寄存器值。 当线程执行时,这些值存储在 CPU 寄存器中,并在执行另一个线程时存储在内存中。
在用户模式调试期间,当前线程通常确定寄存器上下文。 根据当前线程的寄存器解释对调试器命令、扩展和调试信息窗口中注册的任何引用。
在使用以下命令之一执行用户模式调试时,可以将寄存器上下文更改为当前线程以外的值:
在内核模式调试期间,可以使用各种调试器命令来控制注册上下文,包括以下命令:
这些命令不会更改 CPU 寄存器的值。 相反,调试器从内存中的位置检索指定的寄存器上下文。 实际上,调试器只能检索 保存 的寄存器值。 (其他值是动态设置的,不会保存。 保存的值足以重新创建堆栈跟踪。
设置寄存器上下文后,新寄存器上下文用于使用寄存器值的任何命令,例如 k (Display Stack Backtrace) 和 r (Registers) 。
但是,在调试多处理器计算机时,某些命令使你能够指定处理器。 (有关此类命令的详细信息,请参阅 Multiprocessor Syntax.) 如果为命令指定处理器,该命令将使用指定处理器上的活动线程的寄存器上下文,而不是当前寄存器上下文,即使指定的处理器是当前主动处理器也是如此。
此外,如果寄存器上下文与当前处理器模式设置不匹配,则这些命令会生成不正确的或毫无意义的输出。 为了避免输出错误,在更改处理器模式以匹配寄存器上下文之前,依赖于寄存器状态的命令会失败。 若要更改处理器模式,请使用 .effmach (Effective Machine) 命令,
更改寄存器上下文还可以更改本地上下文。 以这种方式,寄存器上下文可能会影响局部变量的显示。
如果发生任何应用程序执行、单步执行或跟踪,则立即重置寄存器上下文以匹配程序计数器的位置。 在用户模式下,如果当前进程或线程发生更改,则注册上下文也会重置。
寄存器上下文会影响堆栈跟踪,因为堆栈跟踪从堆栈指针在基于 x86 的处理器上注册 (esp 的位置开始) 指向。 如果寄存器上下文设置为无效或不可访问的值,则无法获取堆栈跟踪。
可以使用.apply_dbp (将数据断点 应用到上下文) 命令,将处理器断点) (数据断点应用于特定寄存器上下文。
本地上下文
执行程序时,局部变量的含义取决于程序计数器的位置,因为此类变量的范围仅扩展到定义它们的函数。
执行用户模式或内核模式调试时,调试器使用当前函数的范围 (堆栈上的当前帧) 作为本地上下文。 若要更改此上下文,请使用 .frame (设置本地上下文) 命令,或在 “调用”窗口中双击所需的框架。
在用户模式调试中,本地上下文始终是当前线程堆栈跟踪中的帧。 在内核模式调试中,本地上下文始终是当前寄存器上下文线程堆栈跟踪中的帧。
一次只能对本地上下文使用一个堆栈帧。 无法访问其他帧中的局部变量。
如果发生以下任何事件,则会重置本地上下文:
任何程序执行、单步执行或跟踪
任何命令中使用线程分隔符 (~)
对注册上下文的任何更改
使用 !for_each_frame 扩展可以重复执行单个命令,一次用于堆栈中的每个帧。 此命令更改每个帧的本地上下文,执行指定的命令,然后将本地上下文返回到其原始值。