Windows控制台程序文件句柄调试:替代Unix strace的方案问询
刚好有过类似的调试经验,来给你捋清楚怎么用CDB实现类strace的追踪,针对你调试PuTTY DLL的场景:
你尝试的cdb -o "!htrace -enable" <command>存在时机问题:-o参数是用来附加到已有进程,或是启动新进程后立即附加,但!htrace -enable需要等进程加载完内核模块后才能执行,直接写在命令行里会因为环境未初始化报错。如果想要自动启用追踪,应该用-c参数指定启动后执行的命令:
cdb -c "!htrace -enable; g" <你的控制台程序.exe>
这个命令会先启动程序,自动执行句柄追踪启用命令,再让程序继续运行,就解决了时机问题。
!htrace主要是追踪句柄的创建、关闭和泄漏,虽然能间接找到失败的文件操作,但如果只想定位“找不到ggg文件/目录”这类错误,用断点拦截文件创建函数会更高效:
设置条件断点拦截失败的文件调用
在CDB中启动程序后(可以用cdb -g -G <你的程序.exe>跳过初始和终止断点),输入以下命令设置断点:bp kernel32!CreateFileW "j (poi(@eax) = 0xffffffff) '.echo 🔴 CreateFileW调用失败; !gle; k'; g"解释:这个断点会在
CreateFileW执行完成后检查返回值(存在eax寄存器),如果是无效句柄INVALID_HANDLE_VALUE(即0xffffffff),就自动打印错误详情(!gle会获取系统错误码,比如ERROR_FILE_NOT_FOUND)和完整调用栈(k),然后继续运行程序。
如果你的程序用的是ANSI编码的文件接口,把kernel32!CreateFileW换成kernel32!CreateFileA即可。触发场景并查看结果
输入g让程序继续运行,当触发到访问ggg文件的操作时,CDB会自动输出错误信息和调用栈,你就能直接看到是PuTTY DLL中的哪个函数发起的这个失败调用。
如果需要像strace一样追踪所有系统调用,除了CDB,还可以用Windows自带的Process Monitor(ProcMon):
- 启动ProcMon后,过滤你的目标进程,添加“Result”为“NAME NOT FOUND”的过滤条件,就能直观看到所有找不到文件的操作,包括调用栈、发起的模块,甚至能直接定位到PuTTY DLL的代码位置,操作比CDB更直观。
- 如果你必须用调试器,也可以结合
!syscall命令在CDB中追踪系统调用,但步骤会更繁琐。
- 确保你有PuTTY DLL的符号文件(.pdb),在CDB中用
.symfix或.sympath设置符号路径,这样调用栈会显示具体的函数名,而不是晦涩的内存地址。 - 如果程序启动后很快就触发了文件错误,可以用
cdb -c "bp kernel32!CreateFileW; g" <你的程序.exe>,让程序在第一次调用文件创建函数时暂停,再手动设置条件断点。
内容的提问来源于stack exchange,提问作者user2531336

