22.windbg-ln、伪寄存器(Pseudo-Register Syntax)、自定义伪寄存器

本文介绍Windbg中的伪寄存器概念及其使用方法,包括如何查询和设置伪寄存器,如$ip、$ra等,并解释了这些伪寄存器在不同架构下的具体含义。

ln

ln 命令显示给定地址处的或者最近的符号。

ln表示list near,ln命令将尽可能地给出与特定地址相关的符号,如果没有符号能够精确地与这个地址匹配,那么调试器将通过指针算法对靠近这地址的符号进行运逄,

并返回运算结果符号

0:000> ln 01012475
(01012475)   calc!WinMainCRTStartup   |  (0101263c)   calc!__CxxFrameHandler
Exact matches:
    calc!WinMainCRTStartup = <no type information>
0:000> ln 01012475+1
(01012475)   calc!WinMainCRTStartup+0x1   |  (0101263c)   calc!__CxxFrameHandler


我们发现,第一个显示为Exact matches:表示精确匹配了一个地址,如果不是精确匹配,我们要小心,是否模块进行了优化,在优化后,一个函数,可能被拆分为多个部分

分别位于不同的地址,经过优化的映像可以通过lm查看:会有perf标识

当你在查看某部分数据,却不知道这部分数据所表示的内容时,这个命名能带来极大的帮助

 

伪寄存器

伪寄存器都是通过r来操作的
输入Pseudo-Register Syntax查询

对于那些偶尔使用调试器的用户是很难记得所有平台的指令指针寄存器名字(或其他的名字),为了克服这个问题,调试器的开发团队引入了各种伪寄存器,由调试器把这些伪寄存器对应到不同的硬件架构上,形式为$name,与标准的寄存器一样,如果要在表达式中使用伪寄存器,那么必须使用转义字符@

$exentry

当前进程的入口地址

0:002> r $exentry
$exentry=01012475


 一般可以直接在这下断点,

这个就对应PE文件中的ImageBase+AddressOfEntryPoint(_IMAGE_OPTIONAL_HEADER)

$ip

指令指针寄存器

在X86架构上,$ip = eip

在x64架构上,$ip = rip

在Itanium架构上, $ip = iip

 x86/x64/ia-64的区别

0:000> r @$ip
$ip=7c92120e
0:000> r eip
eip=7c92120e

注意到下面显示的分别是$ip,eip,虽然它们在X86下是同一个东东.

$ra

当前函数的返回地址

0:000> r $ra
$ra=7c95e612
0:000> kb
ChildEBP RetAddr  Args to Child              
0012fb1c 7c95e612 7ffdd000 7ffde000 00000000 ntdll!DbgBreakPoint
0012fc94 7c94108f 0012fd30 7c920000 0012fce0 ntdll!LdrpInitializeProcess+0xffa
0012fd1c 7c92e437 0012fd30 7c920000 00000000 ntdll!_LdrpInitialize+0x183
00000000 00000000 00000000 00000000 00000000 ntdll!KiUserApcDispatcher+0x7


其实也是对应当前线程,如果要看所有线程的当前函数的返回地址:

0:000> ~* r $ra
$ra=77d191be
$ra=7c92df2c
$ra=7c92df3c
$ra=7c970010

$retreg

主要的值寄存器,在函数调用返回后,函数的结果将放在这个寄存器中,根据处理器架构的不同,$retreg的值分别为

在x86架构上,$retreg = eax

在x64架构上,$retreg = rax

在Itanium架构上,$retreg = ret0

0:000> r $retreg
$retreg=00251eb4
0:000> r eax
eax=00251eb4

$csp

当前的栈指针,根据处理器架构的不同,$csp的值分别为

在x86架构上,$csp = esp

在x64架构上,$csp = rsp

在Itanium架构上,$csp = bsp

0:000> r $csp
$csp=0012fb24
0:000> r esp
esp=0012fb24

$tpid

当前进程的标识(PID)

0:000> r $tpid
$tpid=000013f4

$tid

当前线程的标识(TID0

0:000> r $tid
$tid=000014a0

伪寄存器描述
$ea 最后一条被执行指令的有效地址(effective address)。如果这条指令没有一个有效地址,将显示"Bad register error"。如果这条指令有两个有效地址,则显示第一个地址。
$ea2 最后一条被执行指令的第二个有效地址,如果这条指令没有两个有效地址,将显示"Bad register error"。
$exp 最后一个被求值的表达式。
$ra 当前堆栈的返回地址。

这个在执行命令中特别有用。例如,g @$ra 将一直执行到返回地址处(虽然,对于“步出(stepping out)”当前函数gu (Go Up)是一个更加准备有效的方法)。
$ip 指令指针寄存器:

x86 处理器:和 eip 相同
Itanium 处理器:涉及 iip(请看表后的注解)
x64处理器:和rip相同
$eventip 当前事件发生时的指令指针,通常和 $ip 匹配,除非你切换了线程或者手动改变了指令指针的值。
$previp 前一个事件发生时的指令指针。(中断进入调试器算做一个事件。)
$relip 和当前事件相关的指令指针,当你正在跟踪分支指令时,这个是分支来源指针。
$scopeip 当前局部上下文(也称为作用域)的指令指针。
$exentry 当前进程的第一个可执行的入口点地址。
$retreg 主要的返回值寄存器:

x86 处理器:和 eax 相同
Itanium 处理器:和 ret0 相同
x64 处理器:和 rax 相同
$retreg64 主要的返回值寄存器,以64位格式。

x86处理器:和edx:eax 相同
$csp 当前调用堆栈指针,是一个通常表示调用堆栈深度的寄存器。

x86 处理器:esp 相同
Itanium 处理器:bsp 相同
x64 处理器:rsp 相同
$p 最后一条 d* (Display Memory)命令打印的值。
$proc 当前进程的地址(换句话说,就是 EPROCESS 块的地址)。
$thread 当前线程的地址(换句话说,就是 ETHREAD 块的地址)。
$peb 当前进程的进程环境块(PEB)的地址。
$teb 当前线程的线程环境块(TEB)的地址。
$tpid 当前线程所在进程的进程 ID(PID)。
$tid 当前线程的线程 ID。
$bpNumber对应断点的地址。例如,$bp3(或者 $bp03)引用断点 ID 为 3 的断点。Number 总是一个十进制数,如果没有哪个断点的 ID 为Number,则$bpNumber 求值为 0,详细请看使用断点
$frame当前帧索引,这个和.frame (Set Local Context) 命令常用的 frame number 相同。
$dbgtime当前时间,根据调试器运行的计算机。
$callret.call (Call Function)命令调用的或者被.fnret /s命令使用的最后函数得到的返回值,$callret 的数据类型就是返回值的数据类型。
$lastclrex 仅托管代码调试: 最近一次遇到的公共语言运行时(CLR)异常对象的地址。
$ptrsize指针大小。在内核模式下,指目标计算机上的指针大小。
$pagesize一个内存页的大小(也就是占用的字节数目),在内核模式下,指目标计算机上的页大小。

自定义伪寄存器

有二十个自定义伪寄存器: $t0, $t1, ..., $t19。它们是可以通过调试器读写的变量。能用来保存任意整数值。做为循环变量时非常有用

0:000> x
0026fb80 argc = 1
0026fb84 argv = 0x002d33a0
0026fb70 p = 0x002d1b90
0:000> r $t0
$t0=00000000
0:000> r $t0 = poi(p)
0:000> r $t0
$t0=002d1b90
除非 r 命令使用了 ? 开关选项,否则一个伪寄存器总是具有整数类型。如果用到了 ? 选项,则伪寄存器可以获得赋给它的任意类型,例如,下面的命令把 UNICODE_STRING** 类型和 0x0012FFBC 值赋给了 $t15(译注:这里好像是 UNICODE_STRING 类型吧!另外,如果 UNICODE_STRING 解析不了,可以用 _UNICODE_STRING)。

0:000> r? $t15 = * (UNICODE_STRING*) 0x12ffbc

下面可以看出r和r?的区别,比如我的代码有个char* g_char = "I am string";

00bc7004 test1!g_char = 0x00bc573c "I am string"
0:000> r? $t0 = test1!g_char
0:000> r $t0
$t0=00bc573c
0:000> r $t1 = test1!g_char
0:000> r $t1
$t1=00bc7004
可以看到$t0保存的是真实的test1!g_char的指针地址,而$t1只是保存了它的对象地址

所以:

0:000> da $t0
00bc573c  "I am string"
0:000> da $t1
00bc7004  "<W."
0:000> da test1!g_char
00bc7004  "<W."
0:000> da poi(test1!g_char)
00bc573c  "I am string"
 自己比对吧



 

<think>我们正在讨论WinDbg中禁用符号加载优化选项(SYMOPT_100)的问题。SYMOPT_100是WinDbg的一个符号选项,它控制符号加载的行为。在WinDbg中,符号选项可以通过`.symopt`命令来查看和修改。SYMOPT_100的具体含义是:忽略符号服务器上的索引,而直接使用符号文件。禁用这个选项(即关闭SYMOPT_100)意味着在从符号服务器加载符号时,会使用索引来加快符号的查找速度。 用户可能遇到的问题是:在调试过程中,符号加载速度慢,或者加载了不正确的符号。通过禁用SYMOPT_100(即关闭该选项),可以尝试使用符号服务器上的索引来加速符号加载,并确保加载正确的符号。 在WinDbg中,我们可以通过以下步骤来禁用SYMOPT_100(注意:禁用SYMOPT_100实际上是关闭这个选项,即从当前符号选项设置中移除SYMOPT_100): 1. 首先,查看当前的符号选项设置:`.symopt` 2. 然后,计算新的符号选项值:当前值 与上 SYMOPT_100的反码(即从当前选项中移除SYMOPT_100) - SYMOPT_100的值为0x100(即256),所以反码为0xFFFFFEFF(在32位下)或0xFFFFFFFFFFFFFEFF(在64位下)。但在WinDbg中,我们通常使用按位操作来移除某个标志。 3. 使用命令:`.symopt- 0x100` 来移除SYMOPT_100标志。 另一种方法是直接设置符号选项值: `.symopt <new_value>` 其中`<new_value>`是新的符号选项的整数值。我们可以先获取当前值,然后减去0x100(如果当前包含SYMOPT_100的话)。 但是,更直接的方法是使用`.symopt-`命令来移除某个选项。 具体步骤: 1. 打开WinDbg。 2.命令窗口中,输入以下命令来查看当前符号选项: ``` .symopt ``` 记下当前的值,并注意是否包含0x100(即SYMOPT_IGNORE_NT_SYMPATH)。 注意:实际上,SYMOPT_100在文档中称为SYMOPT_IGNORE_NT_SYMPATH,但根据Windows调试工具文档,符号选项的常量名称可能有所不同。在最新的文档中,0x100对应的选项是忽略_NT_SYMBOL_PATH环境变量。然而,在较早的文档中,0x100可能对应其他含义。因此,我们需要确认用户使用的WinDbg版本。 根据最新的Windows调试工具文档(WinDbg 10),符号选项常量如下: - 0x100: SYMOPT_IGNORE_NT_SYMPATH - 忽略_NT_SYMBOL_PATH环境变量。 - 0x200: SYMOPT_DEBUG_TYPE_PTR - 用于调试类型指针。 - 等等。 但是,在用户的问题中,SYMOPT_100通常指的是0x100这个选项。不过,在WinDbg中,符号选项的默认设置通常不包括0x100。用户可能希望禁用这个选项,即关闭忽略_NT_SYMBOL_PATH环境变量的功能,从而让调试器使用环境变量中设置的符号路径。 因此,如果用户想要禁用SYMOPT_100(即不再忽略_NT_SYMBOL_PATH),那么应该移除0x100这个标志。 操作命令: ``` .symopt- 0x100 ``` 然后,再次运行`.symopt`来确认0x100已经被移除。 另外,如果用户想要完全重置符号选项,可以使用: ``` .symopt+ 0x80000000 // 恢复默认值(默认值包含一些基本选项) ``` 但注意,默认值中并不包含0x100,所以如果用户只是希望移除0x100,那么直接移除即可。 如果用户遇到符号加载问题,除了调整符号选项,还应该检查符号路径(`.sympath`)设置是否正确,以及符号服务器是否可用。 总结: - 禁用SYMOPT_100(即关闭0x100选项)的命令是:`.symopt- 0x100` - 启用SYMOPT_100(即打开0x100选项)的命令是:`.symopt+ 0x100` 用户的需求是禁用(disable)SYMOPT_100,所以我们使用移除选项的命令。 注意:在WinDbg中,符号选项的修改只影响当前调试会话。 如果用户需要持久化设置,可以考虑在启动WinDbg时通过命令行参数设置,或者使用脚本初始化。 参考文档:[Symbol Options](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/symbol-options) 由于我们无法直接链接外部文档,这里仅提供参考。 相关问题: 1. 如何查看WinDbg中的当前符号选项? 2. 如何设置符号路径(_NT_SYMBOL_PATH)? 3. WinDbg中常见的符号加载问题有哪些? 4. 如何重置WinDbg的符号选项到默认值? 以上问题可以帮助用户进一步了解符号配置和故障排除。</think>### WinDbg 禁用 SYMOPT_100 的步骤 在 WinDbg 中,`SYMOPT_100`(十六进制值 `0x100`)是符号选项(Symbol Options)的一部分,它控制符号加载的行为。禁用此选项通常用于解决符号加载问题或优化调试过程。以下是具体操作步骤: #### 1. **查看当前符号选项** 在 WinDbg 命令窗口中输入: ```windbg .symopt ``` 输出示例: ``` Symbol options: 0x30237 SYMOPT_CASE_INSENSITIVE - on SYMOPT_UNDNAME - on SYMOPT_DEFERRED_LOADS - on SYMOPT_LOAD_LINES - on SYMOPT_OMAP_FIND_NEAREST - on SYMOPT_DEBUG - on ``` 记录十六进制值(如 `0x30237`)[^1]。 #### 2. **禁用 SYMOPT_100** - **方法 1:直接移除标志位** 使用命令: ```windbg .symopt- 0x100 ``` 这会从当前符号选项中减去 `0x100`。 - **方法 2:手动计算新值** 若当前值为 `0x30237`,禁用 `0x100` 后的新值为: $$ \text{新值} = \text{原值} \ \& \ \sim\text{0x100} = \text{0x30237} \ \& \ \text{0xFFFFFEFF} = \text{0x30137} $$ 然后显式设置: ```windbg .symopt 0x30137 ``` #### 3. **验证是否禁用** 再次运行: ```windbg .symopt ``` 检查输出中是否包含 `SYMOPT_IGNORE_NT_SYMPATH`(即 `0x100` 的别名),确保该选项已消失[^2]。 --- ### 关键说明 - **作用**:`SYMOPT_100`(`SYMOPT_IGNORE_NT_SYMPATH`)会忽略 `_NT_SYMBOL_PATH` 环境变量。禁用后,WinDbg 将重新遵守该变量指定的符号路径。 - **应用场景**: - 解决符号加载失败问题(如 `PDB not found`)。 - 强制使用本地符号缓存而非远程服务器。 - 调试时需动态切换符号路径。 - **持久性**:此修改仅对当前调试会话有效。重启 WinDbg 后需重新配置。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值