几天前,我在工作中遇到了这个问题,我想知道是否有一种方法可以从这个场景中生成更多的数据,而不是去微软。有很多这样的情况,我想探索,作为一个windows开发人员,什么是最好的/最佳的方式来获取大部分的信息是这样的情况。我来描述一下情况:
-
一个办公应用程序,在打印某些设置(涉及cmyk色彩空间)时,弹出一个描述错误的对话框。"文件%s无法打开,因为它被其他应用程序锁定了"。它不提供文件名,事件查看器也不提供。打印失败
-
在使用
procmon
时,我们发现"文件锁定错误";当apiCreatefileMapping
被office应用程序、假脱机程序、splwow64.exe(是的,它是64位系统,应用程序是32位)等相关进程调用时, -
当没有splwow64时问题不存在,意味着在64位操作系统上使用64位应用程序。
我想知道在这种情况下哪些工具对获取更多信息有用。这包括使用MS符号与windbg和调试汇编,如果需要的话。基本上,我需要锁定的文件名(显示为%s)和问题的根源。
没有源代码和符号的调试是困难的。所采取的方法因你所能观察到的和你所能做出的假设而异。以下内容听起来很符合你的情况。
将64位文件访问与32位版本进行比较
由于64位版本工作,看看文件访问的差异是什么。您可以将Process Monitor日志导出为CSV格式,并编写分析文件访问的工具。您的分析工具可能应该
- 将多个具有不同偏移量的文件读取访问汇总为对整个文件的单个文件访问。
- 忽略读顺序,因为顺序似乎不太重要。
- 首先忽略dll
也许你甚至可以在Excel中这样做。
捕获文件访问调用
首先,我认为使用Process Monitor已经是一个很好的方法。你可以在不了解应用程序的情况下发现它在做什么,所以这将是我的首选。
当然,要缩小问题文件的范围是很困难的。如果有必要,你需要遍历所有这些文件,例如,在批处理文件的帮助下,找到一个命令行工具,它可以帮助找到打开该文件的应用程序。在这种情况下,请查看SysInternals Handle。它是一个命令行实用程序,您可以给它一个文件名。基本上,它是Process Explorer的命令行版本(见下文)。
读取文件和写入文件通常通过API调用完成,因此API Monitor是另一个选项。筛选所有可疑的文件访问方法(ReadFile, ReadFileEx, LockFile, LockFileEx, WriteFile, WriteFileEx,…)
这也可以在WinDbg中通过设置断点来实现,但是你可能会经常碰到它们,所以处理它们可能需要一些自动化。
bp
命令可以指定一个命令字符串。是幸运可能发生的情况是,打算用作%s
格式字符串参数的文件名在内存中的某个地方。
- 在应用程序显示消息 时进行崩溃转储
- 使用SysInternals Strings实用程序转储转储的所有字符串。
- 直接过滤
C:
,D:
等的输出,通过管道将其传输到find
命令或将其重定向到文本文件以供以后分析
这仍然会给您留下大量文件,因此找到罪魁祸首并不比使用前一种方法容易得多。同样,使用其他工具缩小列表范围,例如handle
。
- 在应用程序显示消息 时进行崩溃转储
- 在WinDbg 中打开转储文件
- 转储您在堆栈上找到的一些地址的字符串。由于NTFS中的文件名是Unicode,所以
du <address>
在这里应该可以正常工作。
这肯定需要更多的内部知识,例如在哪里找到好的指针等。
分析第一次机会异常
如果应用程序依赖于异常,您可以通过检查第一次出现的异常来了解一些情况。但是,如果应用程序做了良好的前提条件检查,则会有更少的异常,从而降低捕获有用信息的机会。
如果情况重现良好,你可以
- 使用图像文件执行选项设置WinDbg作为该进程的调试器。
- 使用
.logopen /t /u c:firstchanceexceptions.log
打开日志文件 - 使用
sxe -c ".exr -1;k;g" *
转储所有异常。该命令中的g
将立即继续,以便应用程序(希望)不会遇到超时。 - 继续执行
g
- 当应用程序终止时,使用
.logclose
关闭日志文件 - 查看日志文件中有趣的异常/有趣的调用堆栈
- 重现错误,但这次停止在有趣的异常
- 查看方法参数和内存是否找到文件名(再次使用
du <address>
)
查找属于消息框的应用程序
如果你不能找出显示错误信息的应用程序,例如,因为错误的消息标题,这样做:
下载SysInternals Process Explorer并运行。
将工具栏上的十字线拖到窗口上方。
进程资源管理器现在突出显示拥有该窗口的可执行文件
如果打印文件名,查找锁定应用程序
如果对话框显示文件名而不仅仅是"%s":
也使用进程资源管理器
使用查找/查找句柄或DLL或按Ctrl+F
输入文件名或部分文件名