分类 调试 下的文章

当我们通过各种手段获取到一个Windows错误码后,如何获取对应的错误消息呢?有两种方法:一是用编程的手段(FormatMessage);其二是用现成的工具。第一种方法一般在我们编码的时候有用,而更多情况下我们进行调试得到了错误码,不可能还要先写一段代码,而是直接用工具去快速获取了。

一、VS自带工具---errlook.exe

当我们安装了VS开发工具就有,一般放在..\Microsoft Visual Studio XX\Common7\Tools目录下

运行的界面如下:

如果是Win32 Error Code,直接输入错误码就行,可以是十进制也可以是十六进制

注意,当我们输入一个值查不到时,比如0xC0000005

如果我们确定这是一个错误值的话,可以添加对应的模块,在进行查找

 二、Error Lookup

Error Lookup是一款国外的系统错误或蓝屏问查询工具,平时使用电脑中偶尔会有出错提示,在出错的时候会有一串你看不明白的代码,同理电脑蓝屏的时候也会有一串错误代码,只要把这些代码粘贴到软件中即可查询到是因为什么原因而出错,找到原因才可以解决错误的问题。下载地址http://www.jisuxz.com/down/66543.html

运行界面如下:

它显示了更多的错误信息,不仅仅时错误消息

 

这个工具不用自己去选择错误代码对应的模块,它会默认加载很多常用模块

 还可以切换语言

三、Windows Error Lookup Tool

是一款非常不催的错误代码查询软件。如何查询错误的代码呢?那么不妨来看看这款Windows Error Lookup Tool。该款工具能够帮助您在编程时间最快找出错误代码,提高您的编程效率。使用方法也很简单,用户只需在软件界面中输入错误代码,它会自动显示这个错误代码的含义或类型等详细信息。下载地址http://www.jz5u.com/Soft/system/Other/206870.html

运行界面如下:

也是自动加载了常用模块,不用用户自己去加载了

四、网络错误查找命令

net helpmsg #

是将Windows错误代码转换为字符串的一种快速的方法。只能输入十进制的错误代码,它只在Windows错误代码上运行。它不解码hresult或ntstatus值,不支持带有插入的消息,大概是因为它没有传递FORMAT_MESSAGE_IGNORE_INSERTS标识。

使用举例

当输入16进制代码时

 

 

总之,可以根据情况合理选择工具。

“托管调试器(如Visual Studio)的哪些版本可以调试哪些版本的CLR?怎么办?”


这是调试器版本控制的基本问题。


以下是从版本控制的角度来看的“调试堆栈”,包括每个层之间的协议和进程边界:

  1. 用户源代码协议:
    由编译器处理的源语言。---编译器/调试对象进程边界----
  2. 正在调试的用户应用程序。
    协议:IL操作码,元数据。这些都在ECMA标准中公开定义。
  3. 运行应用程序的CLR。(mscorwks.dll)协议:
    专用CLR调试通信。---调试对象/调试器进程边界----
  4. CLR调试API(ICorDebug)(mscordbi.dll)
    协议:公共ICorDebug API。这是一个高版本的COM经典API。
  5. 调试器,如visualstudio或MDbg。
    协议:任意调试器扩展接口。也可能暴露ICorDebug。
  6. 调试器扩展、表达式计算器等。

所以这里可能有6个不同的组件可以被版本化!


加载哪个CLR?


生成一个单独的进程,它将在一个单独的进程中执行。

加载的CLR版本由shim/loader/config策略确定。调试器在这里是不可知的,尽管它确实可以做一些事情来影响这一点,比如在启动应用程序之前放置配置文件。由于托管可执行文件是IL操作码和元数据,这些都是经过很好指定的,因此有一些版本控制选项可用于编译.NET版本X的应用程序,但在.NET版本Y上运行它。例如,为.NET 1.1编译的应用程序可以在.NET 2.0上运行。

加载哪个ICorDebug?

一旦CLR版本(mscorwks.dll)确定后,下一个问题变成:调试器加载哪个mscordbi?


我们选择在ICorDebug而不是专用协议上对调试进行版本设置:

-ICorDebug已经是一个公共的comapi,并且已经通过像QueryInterface这样的东西来进行版本控制。

-这减少了测试组合。允许混合和匹配mscorwks.dll一个武断的mscordbi.dll会产生一个不断增长的测试矩阵。如果mscordbi.dll如果需要能够调试mscorwks的多个版本,它的复杂性将不断增加。

-这使得CLR可以在私有CLR调试协议上自由创新。它的一个优点是,它允许我们调整协议的聊天时间。


结果就是mscordbi.dll必须选择以匹配的版本mscorwks.dll那是装的。这是在第一次通过CreateDebuggingInterfaceFromVersion创建ICorDebug对象时完成的。

ICorDebug


调试器通常需要是最新版本,以便能够理解它在调试对象中看到的内容。例如,在V2中添加了泛型。V1.1调试器很难在V2应用程序中看到泛型。现在,关于是否可以通过“优雅的降级”来缓解这种混乱,通常是通过:

-让调试器忽略它不理解的内容(例如,不要在调用堆栈中显示泛型方法)

-构造一个近似的V2。

有时这些技术可以奏效,但这是一个非常滑的斜坡。
这就是VS2003无法调试.NET2.0应用程序的原因。

 

来自Windows调试工具包的所有调试程序都使用相同的引擎dbgeng.dll。它包含一种特殊语言的脚本解释器,我们称之为WinDbg脚本语言以方便使用,我们对WinDbg脚本文件使用WDS文件扩展名。下面是在分析一个脚本时捕获的WinDbg线程的调用堆栈:

0:000> ~1kL 100ChildEBP RetAddr   
037cd084 6dd28cdc dbgeng
!TypedData::ForceU64+0x3037cd0ec 6dcbd08c dbgeng!GetPseudoOrRegVal+0x11c037cd134 6dcbceff dbgeng!MasmEvalExpression::GetTerm+0x12c037cd198 6dcbca23 dbgeng!MasmEvalExpression::GetMterm+0x36f037cd1d4 6dcbc873 dbgeng!MasmEvalExpression::GetAterm+0x13037cd220 6dcbc783 dbgeng!MasmEvalExpression::GetShiftTerm+0x13037cd254 6dcbc523 dbgeng!MasmEvalExpression::GetLterm+0x13037cd2c0 6dcbc443 dbgeng!MasmEvalExpression::GetLRterm+0x13037cd2f4 6dcbc424 dbgeng!MasmEvalExpression::StartExpr+0x13037cd308 6dcbbc2f dbgeng!MasmEvalExpression::GetCommonExpression+0xc4037cd31c 6dccdca3 dbgeng!MasmEvalExpression::Evaluate+0x4f037cd390 6dccd83d dbgeng!EvalExpression::EvalNum+0x63037cd3d0 6dd293cc dbgeng!GetExpression+0x5d037cd458 6dd2a7e2 dbgeng!ScanRegVal+0xfc037cd4ec 6dd17502 dbgeng!ParseRegCmd+0x422037cd52c 6dd194e8 dbgeng!WrapParseRegCmd+0x92037cd608 6dc8ed19 dbgeng!ProcessCommands+0x1278037cd644 6dc962af dbgeng!DotFor+0x1d9037cd658 6dd1872e dbgeng!DotCommand+0x3f037cd738 6dd19b49 dbgeng!ProcessCommands+0x4be037cd77c 6dc5c879 dbgeng!ProcessCommandsAndCatch+0x49037cdc14 6dd19cc3 dbgeng!Execute+0x2b9037cdc64 6dc89db0 dbgeng!ProcessCurBraceBlock+0xa3037cdc74 6dc962af dbgeng!DotBlock+0x10037cdc88 6dd1872e dbgeng!DotCommand+0x3f037cdd68 6dd19b49 dbgeng!ProcessCommands+0x4be037cddac 6dc5c879 dbgeng!ProcessCommandsAndCatch+0x49037ce244 6dd173ca dbgeng!Execute+0x2b9037ce2c4 6dd1863c dbgeng!ParseDollar+0x29a037ce3a0 6dd19b49 dbgeng!ProcessCommands+0x3cc037ce3e4 6dc5c879 dbgeng!ProcessCommandsAndCatch+0x49037ce87c 6dc5cada dbgeng!Execute+0x2b9037ce8ac00318693 dbgeng!DebugClient::ExecuteWide+0x6a037ce954 00318b83 windbg!ProcessCommand+0x143037cf968 0031ae46 windbg!ProcessEngineCommands+0xa3037cf97c 76fa19f1 windbg!EngineLoop+0x366037cf988 77c8d109 kernel32!BaseThreadInitThunk+0xe037cf9c800000000 ntdll!_RtlUserThreadStart+0x23

一、NTSTATUS

直译就是NT状态,也就是内核状态。主要是内核开发/驱动开发用到的API返回的状态。许多内核模式的标准驱动程序例程和驱动程序支持例程使用ntstatus类型作为返回值。此外,当完成IRP时,驱动程序在IRP的IO状态块结构中提供一个ntstatus类型的值。 ntstatus值分为四种类型:成功值、信息值、警告和错误值.

二、NTSTATUS Code

同样是一个32bit的值,大多数的值也是定义了默认的错误消息。它的构成如下:

Sev (2 bits):严重性.


Value

Meaning

STATUS_SEVERITY_SUCCESS

0x0

Success

STATUS_SEVERITY_INFORMATIONAL

0x1

Informational

STATUS_SEVERITY_WARNING

0x2

Warning

STATUS_SEVERITY_ERROR

0x3

Error

当调试代码中的一个讨厌的问题时,你能得到的最有用的东西之一就是一个小型转储。当你的应用程序在崩溃、挂起或内存开始激增时,你得到了一个很大的提示,可以开始你的探索。虽然有很多工具,比如奇妙的prodump,以及调试器自己来创建小转储,但真正的关键时刻是您必须查看这些小型转储。一个或两个很容易做到,但是如果你有200个呢?在我的工作领域,我调试别人的软件问题,我通常会面对来自客户的数百个转储。尽管我很想仔细打开每个小型垃圾场,并且一遍又一遍地输入相同的命令。
我真正需要的是这样一种方式:“这里有一堆.DMP文件;在所有这些文件中运行这些WinDBG命令。”事实证明,当你结合一点WinDBG知识和一点PowerShell魔法时,完成这项基本任务一点都不难。在开始使用脚本之前,我需要谈谈它是如何工作的。这样你就能更好地理解它的用法。

为了编写WinDBG脚本,以便它在一个文件中执行一组命令,使用$$<命令就可以做到这一点。该命令将读入一个文本文件,并依次执行每一行,就像您在命令区域中键入了它一样。您可以在WinDBG帮助中找到$$<的其他变体,它们提供了稍微不同的功能,但是这个命令对于我来说已经足够了。

如果我想运行!analyze并获取已加载模块的列表,下面的调试脚本文本文件名为,BasicAnalysis.txt,显示这些命令。星号被认为是$$<的注释行。

    * Run !analyze!analyze v*Get the list of loaded modules
lmv