摘要
最近在调试的时候想查看 mfc140u.dll 中的函数,发现对应的调试符号没有加载,手动加载了几次都是失败。再三确认调试符号确实存在,而且设置的符号路径都对。难道又是调试符号不匹配?于是打算用 chkmatch 确认一下是否匹配。
最后,发现是调试符号放到了 system32 路径下,chkmatch 是 32 位程序,会自动到 sysWOW64 目录下找。本文简单记录了使用 procmon 快速排查定位,最后使用 chkmatch -c 使调试符号与 mfc140u.dll 强制匹配的过程。
初遇问题
今天调试的时候,又是找不到 mfc140u.dll 的符号,如下图:

但是有一个很重要的逻辑需要查看该模块中的代码。于是手动加载了几次,再三确认了调试符号确实存在,而且符号路径设置的确实正确。很有可能是符号不匹配导致的。于是想着用 chkmatch 检查一下。
chkmatch 报错
没想到,运行 chkmatch 的时候却报找不到调试符号。

明明 mfc140u.amd64.pdb 就在 c:\windows\system32 目录下,但 chkmatch 为什么却找不到呢?看来需要请 procmon 出马了。
procmon 出马
运行 procmon,然后执行 chkmatch,执行完成后,停止采集。根据进程名过滤后,只保留文件读写操作。很快就看到了关键的事件。

从 Path 一列,可以清楚的知道,chkmatch 访问的是 c:\windows\sysWOW64\mfc140u.amd64.pdb,而不是 c:\windows\system32\mfc140u.amd64.pdb。
看到这里,我恍然大悟,在 64 位系统下运行的 32 位进程访问注册表和文件路径时会发生重定向。
强制匹配
把 mfc140u.amd64.pdb 拷贝到其它路径下,然后再次执行检查操作,发现确实是调试符号不匹配导致的 mfc140u.dll 加载符号失败。
chkmatch 不仅可以检查调试符号是否匹配,还可以修改调试符号的关键信息,使其与对应的模块文件强制匹配。只需要把 -c 选项换成 -m 选项即可。把修改后的调试符号放到 d:\share\dll-pdbs\ 路径下,并在 vs 中设置好调试符号路径,然后右键,重新加载调试符号,这次可以看到期盼已久的函数名及对应的源码了。
总结
procmon 是监控各种操作的神器
chkmatch 不仅可以检查调试符号是否匹配,还可修改调试符号信息使其匹配