如何调试---写给一0基础的同学
了解如何调试是每个应用程序开发生命周期的一个关键方面。通过调试,开发人员不仅可以识别出发生了异常,还可以系统地遍历应用程序的执行,直到找到并修复罪魁祸首代码。无论解决方案是否需要修复一个小的错误,甚至需要重写系统中的大量组件,只要有足够的时间和人力,简单的调试操作就可以(最终)解决几乎所有问题。
然而,尽管调试功能强大,但它也有点难以承受。由于在几十个代码编辑器和集成开发环境(ide)中使用了数百种活动编程语言和框架,在开始调试自己的项目时,确切地知道如何开始可能有些令人吃惊。
我们去调试吧!
单步操作
交叉引用:Microsoft.NET标准异常 和错误代码对照表
简介
此表旨在帮助将Windows运行时应用程序错误代码交叉引用到Microsoft.NET标准异常,这些异常可以作为应用程序异常处理技术的一部分。
对照表
.NET Exception (Namespace)
HRESULT(s) - symbolic
HRESULT(s) - raw
AccessViolationException
E_POINTER
0x80004003
AmbiguousMatchException (System.Reflection)
COR_E_AMBIGUOUSMATCH
0x8000211d
ApplicationException
COR_E_APPLICATION
0x80131600
AppDomainUnloadedException
COR_E_APPDOMAINUNLOADED
0x80131014
ArithmeticException
COR_E_ARITHMETIC
0x80070216
ArgumentException
COR_E_ARGUMENT
0x80070057
ArgumentNullException
E_POINTER
0x80004003
ArgumentOutOfRangeException
COR_E_ARGUMENTOUTOFRANGE
0x80131502
ERROR_NO_UNICODE_TRANSLATION
0x80070459
ArrayTypeMismatchException
COR_E_ARRAYTYPEMISMATCH
0x80131503
BadImageFormatException
COR_E_BADIMAGEFORMAT
0x8007000b
CLDB_E_FILE_OLDVER
0x80131107
CLDB_E_INDEX_NOTFOUND
0x80131124
CLDB_E_FILE_CORRUPT
0x8013110e
COR_E_NEWER_RUNTIME
0x8013101b
COR_E_ASSEMBLYEXPECTED
0x80131018
ERROR_BAD_EXE_FORMAT
0x800700c1
ERROR_EXE_MARKED_INVALID
0x800700c0
CORSEC_E_INVALID_IMAGE_FORMAT
0x8013141d
ERROR_NOACCESS
0x800703e6
ERROR_INVALID_ORDINAL
0x800700b6
ERROR_INVALID_DLL
0x80070482
ERROR_FILE_CORRUPT
0x80070570
COR_E_LOADING_REFERENCE_ASSEMBLY
0x80131058
META_E_BAD_SIGNATURE
0x80131192
CannotUnloadAppDomainException
COR_E_CANNOTUNLOADAPPDOMAIN
0x80131015
ContractException (System.Diagnostics.Contracts)
COR_E_CODECONTRACTFAILED
0x80131542
ContextMarshalException (System)
COR_E_CONTEXTMARSHAL
0x80131504
CustomAttributeFormatException (System.Reflection)
COR_E_CUSTOMATTRIBUTEFORMAT
0x80131605
CryptographicException (System.Security.Cryptography)
CORSEC_E_CRYPTO
0x80131430
CryptographicUnexpectedOperationException (System.Security.Cryptography)
CORSEC_E_CRYPTO_UNEX_OPER
0x80131431
DataMisalignedException
COR_E_DATAMISALIGNED
0x80131541
DirectoryNotFoundException (System.IO)
COR_E_DIRECTORYNOTFOUND
0x80070003
STG_E_PATHNOTFOUND
0x80030003
CTL_E_PATHNOTFOUND
0x800a004c
DivideByZeroException
COR_E_DIVIDEBYZERO
0x80020012
CTL_E_DIVISIONBYZERO
0x800a000b
DllNotFoundException
COR_E_DLLNOTFOUND
0x80131524
DuplicateWaitObjectException
COR_E_DUPLICATEWAITOBJECT
0x80131529
EndOfStreamException (System.IO)
COR_E_ENDOFSTREAM
0x80070026
EntryPointNotFoundException
COR_E_ENTRYPOINTNOTFOUND
0x80131523
Exception
COR_E_EXCEPTION
0x80131500
ExecutionEngineException
COR_E_EXECUTIONENGINE
0x80131506
FieldAccessException
COR_E_FIELDACCESS
0x80131507
FileLoadException (System.IO)
COR_E_FILELOAD
0x80131621
FUSION_E_INVALID_PRIVATE_ASM_LOCATION
0x80131041
FUSION_E_SIGNATURE_CHECK_FAILED
0x80131045
FUSION_E_LOADFROM_BLOCKED
0x80131051
FUSION_E_CACHEFILE_FAILED
0x80131052
FUSION_E_ASM_MODULE_MISSING
0x80131042
FUSION_E_INVALID_NAME
0x80131047
FUSION_E_PRIVATE_ASM_DISALLOWED
0x80131044
FUSION_E_HOST_GAC_ASM_MISMATCH
0x80131050
COR_E_MODULE_HASH_CHECK_FAILED
0x80131039
FUSION_E_REF_DEF_MISMATCH
0x80131040
SECURITY_E_INCOMPATIBLE_SHARE
0x80131401
SECURITY_E_INCOMPATIBLE_EVIDENCE
0x80131403
SECURITY_E_UNVERIFIABLE
0x80131402
COR_E_FIXUPSINEXE
0x80131019
ERROR_TOO_MANY_OPEN_FILES
0x80070004
ERROR_SHARING_VIOLATION
0x80070020
ERROR_LOCK_VIOLATION
0x80070021
ERROR_OPEN_FAILED
0x8007006e
ERROR_DISK_CORRUPT
0x80070571
ERROR_UNRECOGNIZED_VOLUME
0x800703ed
ERROR_DLL_INIT_FAILED
0x8007045a
FUSION_E_CODE_DOWNLOAD_DISABLED
0x80131048
CORSEC_E_MISSING_STRONGNAME
0x8013141b
MSEE_E_ASSEMBLYLOADINPROGRESS
0x80131016
ERROR_FILE_INVALID
0x800703ee
FileNotFoundException (System.IO)
ERROR_FILE_NOT_FOUND
0x80070002
ERROR_MOD_NOT_FOUND
0x8007007e
ERROR_INVALID_NAME
0x8007007b
CTL_E_FILENOTFOUND
0x800a0035
ERROR_PATH_NOT_FOUND
0x80070003
ERROR_BAD_NET_NAME
0x80070043
ERROR_BAD_NETPATH
0x80070035
ERROR_NOT_READY
0x80070015
ERROR_WRONG_TARGET_NAME
0x80070574
INET_E_UNKNOWN_PROTOCOL
0x800c000d
INET_E_CONNECTION_TIMEOUT
0x800c000b
INET_E_CANNOT_CONNECT
0x800c0004
INET_E_RESOURCE_NOT_FOUND
0x800c0005
INET_E_OBJECT_NOT_FOUND
0x800c0006
INET_E_DOWNLOAD_FAILURE
0x800c0008
INET_E_DATA_NOT_AVAILABLE
0x800c0007
ERROR_DLL_NOT_FOUND
0x80070485
CLR_E_BIND_ASSEMBLY_VERSION_TOO_LOW
0x80132000
CLR_E_BIND_ASSEMBLY_PUBLIC_KEY_MISMATCH
0x80132001
CLR_E_BIND_ASSEMBLY_NOT_FOUND
0x80132004
FormatException
COR_E_FORMAT
0x80131537
IndexOutOfRangeException
COR_E_INDEXOUTOFRANGE
0x80131508
InsufficientExecutionStackException
COR_E_INSUFFICIENTEXECUTIONSTACK
0x80131578
InvalidCastException
COR_E_INVALIDCAST
0x80004002
InvalidComObjectException (System.Runtime.InteropServices)
COR_E_INVALIDCOMOBJECT
0x80131527
InvalidFilterCriteriaException (System.Reflection)
COR_E_INVALIDFILTERCRITERIA
0x80131601
InvalidOleVariantTypeException (System.Runtime.InteropServices)
COR_E_INVALIDOLEVARIANTTYPE
0x80131531
InvalidOperationException
COR_E_INVALIDOPERATION
0x80131509
InvalidProgramException
COR_E_INVALIDPROGRAM
0x8013153a
IOException (System.IO)
COR_E_IO
0x80131620
CTL_E_DEVICEIOERROR
0x800a0039
IsolatedStorageException (System.IO.IsolatedStorage)
ISS_E_ISOSTORE
0x80131450
ISS_E_OPEN_STORE_FILE
0x80131460
ISS_E_OPEN_FILE_MAPPING
0x80131461
ISS_E_MAP_VIEW_OF_FILE
0x80131462
ISS_E_GET_FILE_SIZE
0x80131463
ISS_E_CREATE_MUTEX
0x80131464
ISS_E_LOCK_FAILED
0x80131465
ISS_E_FILE_WRITE
0x80131466
ISS_E_SET_FILE_POINTER
0x80131467
ISS_E_CREATE_DIR
0x80131468
ISS_E_CORRUPTED_STORE_FILE
0x80131480
ISS_E_STORE_VERSION
0x80131481
ISS_E_FILE_NOT_MAPPED
0x80131482
ISS_E_BLOCK_SIZE_TOO_SMALL
0x80131483
ISS_E_ALLOC_TOO_LARGE
0x80131484
ISS_E_USAGE_WILL_EXCEED_QUOTA
0x80131485
ISS_E_TABLE_ROW_NOT_FOUND
0x80131486
ISS_E_DEPRECATE
0x801314a0
ISS_E_CALLER
0x801314a1
ISS_E_PATH_LENGTH
0x801314a2
ISS_E_MACHINE
0x801314a3
ISS_E_STORE_NOT_OPEN
0x80131469
ISS_E_MACHINE_DACL
0x801314a4
MarshalDirectiveException (System.Runtime.InteropServices)
COR_E_MARSHALDIRECTIVE
0x80131535
MethodAccessException
COR_E_METHODACCESS
0x80131510
META_E_CA_FRIENDS_SN_REQUIRED
0x801311e6
MemberAccessException
COR_E_MEMBERACCESS
0x8013151a
MissingFieldException
COR_E_MISSINGFIELD
0x80131511
MissingManifestResourceException (System.Resources)
COR_E_MISSINGMANIFESTRESOURCE
0x80131532
MissingMemberException
COR_E_MISSINGMEMBER
0x80131512
MissingMethodException
COR_E_MISSINGMETHOD
0x80131513
MulticastNotSupportedException
COR_E_MULTICASTNOTSUPPORTED
0x80131514
NotFiniteNumberException
COR_E_NOTFINITENUMBER
0x80131528
NotImplementedException
E_NOTIMPL
0x80004001
NotSupportedException
COR_E_NOTSUPPORTED
0x80131515
NullReferenceException
COR_E_NULLREFERENCE
0x80004003
ObjectDisposedException
COR_E_OBJECTDISPOSED
0x80131622
RO_E_CLOSED
0x80000013
OperationCanceledException
COR_E_OPERATIONCANCELED
0x8013153b
OutOfMemoryException
E_OUTOFMEMORY
0x8007000e
CTL_E_OUTOFMEMORY
0x800a0007
OverflowException
COR_E_OVERFLOW
0x80131516
CTL_E_OVERFLOW
0x800a0006
PathTooLongException (System.IO)
COR_E_PATHTOOLONG
0x800700ce
PlatformNotSupportedException
COR_E_PLATFORMNOTSUPPORTED
0x80131539
System.RankException
COR_E_RANK
0x80131517
ReflectionTypeLoadException (System.Reflection)
COR_E_REFLECTIONTYPELOAD
0x80131602
RemotingException (System.Runtime.Remoting)
COR_E_REMOTING
0x8013150b
RuntimeWrappedException (System.Runtime.CompilerServices)
COR_E_RUNTIMEWRAPPED
0x8013153e
ServerException (System.Runtime.Remoting)
COR_E_SERVER
0x8013150e
SecurityException (System.Security)
COR_E_SECURITY
0x8013150a
CORSEC_E_INVALID_STRONGNAME
0x8013141a
CTL_E_PERMISSIONDENIED
0x800a0046
CORSEC_E_INVALID_PUBLICKEY
0x8013141e
CORSEC_E_SIGNATURE_MISMATCH
0x80131420
SafeArrayRankMismatchException System.Runtime.InteropServices)
COR_E_SAFEARRAYRANKMISMATCH
0x80131538
SafeArrayTypeMismatchException (System.Runtime.InteropServices)
COR_E_SAFEARRAYTYPEMISMATCH
0x80131533
SerializationException (System.Runtime.Serialization)
COR_E_SERIALIZATION
0x8013150c
StackOverflowException
COR_E_STACKOVERFLOW
0x800703e9
CTL_E_OUTOFSTACKSPACE
0x800a001c
SynchronizationLockException (System.Threading)
COR_E_SYNCHRONIZATIONLOCK
0x80131518
SystemException
COR_E_SYSTEM
0x80131501
TargetException (System.Reflection)
COR_E_TARGET
0x80131603
TargetInvocationException (System.Reflection)
COR_E_TARGETINVOCATION
0x80131604
TargetParameterCountException (System.Reflection)
COR_E_TARGETPARAMCOUNT
0x8002000e
ThreadAbortException (System.Threading)
COR_E_THREADABORTED
0x80131530
ThreadInterruptedException (System.Threading)
COR_E_THREADINTERRUPTED
0x80131519
ThreadStateException (System.Threading)
COR_E_THREADSTATE
0x80131520
ThreadStartException (System.Threading)
COR_E_THREADSTART
0x80131525
TypeAccessException
COR_E_TYPEACCESS
0x80131543
TypeInitializationException
COR_E_TYPEINITIALIZATION
0x80131534
TypeLoadException
COR_E_TYPELOAD
0x80131522
RO_E_METADATA_NAME_NOT_FOUND
0x8000000f
CLR_E_BIND_TYPE_NOT_FOUND
0x80132005
TypeUnloadedException
COR_E_TYPEUNLOADED
0x80131013
UnauthorizedAccessException
COR_E_UNAUTHORIZEDACCESS
0x80070005
CTL_E_PATHFILEACCESSERROR
0x800a004b
VerificationException (System.Security)
COR_E_VERIFICATION
0x8013150d
PolicyException (System.Security.Policy)
CORSEC_E_POLICY_EXCEPTION
0x80131416
CORSEC_E_NO_EXEC_PERM
0x80131418
CORSEC_E_MIN_GRANT_FAIL
0x80131417
XmlSyntaxException (System.Security)
CORSEC_E_XMLSYNTAX
0x80131419
COMException (System.Runtime.InteropServices)
E_FAIL
0x80004005
ExternalException (System.Runtime.InteropServices)
E_FAIL
0x80004005
SEHException (System.Runtime.InteropServices)
E_FAIL
0x80004005
ElementNotAvailableException (Windows.UI.Xaml.Automation)
(none)
0x802b001f
ElementNotEnabledException (Windows.UI.Xaml.Automation)
(none)
0x802b001e
LayoutCycleException (Windows.UI.Xaml)
(none)
0x802b0014
XamlParseException (Windows.UI.Xaml.Markup)
(none)
0x802b000a
说明
在上表的“.NET异常”列中,如果链接了异常名称,则该异常是.NET for Windows运行时应用程序类的一部分。这意味着您可以在自己的代码中引发该类型的新异常。或者您可以捕获这些异常,特别是作为try-catch或UnhandledException异常处理的一部分。如果未链接异常名称,则该异常不属于.NET for Windows运行时类的一部分。不属于.NET for Windows运行时集的异常可能在某些互操作方案中遇到,也可能来自系统或Windows运行时内部。您将无法使用该特定异常类型为它们编写捕获块,因为您为Windows运行时应用程序运行的.NET库不知道该类型。但是您仍然可以读取一个HRESULT代码,从“HRESULT(s)-raw:”列中查找它,并注意到有一个对应的.NET异常。或者你可以把它当作一般的例外。然后,您可以阅读.NET文档,或许可以了解有关该异常的意图以及原始代码引发该异常的原因的更多信息,即使该异常未在.NET for Windows运行时类型中表示。如果没有为.NET异常列出命名空间,则它来自系统命名空间。
“HRESULT(s)-symbolic”列中列出的常量来自多种来源。有些是在winerror.h中定义的,有些是在特定于组件对象模型(COM)编程的头文件中定义的,有些是在属于Windows特定子系统的头文件中定义的。有些需要HRESULT_From_Win32宏用法,其中包含来自更早的常量集的代码(前面是ERROR_)。对于使用.NET语言时的典型Windows运行时编程,这些头文件不是作为项目的一部分提供的。如果您正在获取系统无法映射到标准异常的情况下的错误代码信息,则可能会将其视为原始整数或十六进制值,并且不会自动支持将数字代码别名为Windows命名的常量值。尽管如此,在以前的Windows错误报告系统的基础上,仍然存在按其命名常量而不是原始代码引用错误代码的历史。您可以使用表中的命名常量进一步研究其他文档源(如论坛或支持文档)中的错误,特别是该错误对桌面编程、Microsoft Win32和COM等意味着什么。
SystemException:在原始的.NET异常层次结构中,许多异常是从系统异常派生的。例如,从SystemException派生的System.ArgumentException。从SystemException继承表明.NET核心定义了异常。Windows运行时的.NET类集合中未包含系统异常。所有在完整框架下从SystemException派生的异常都是从System.Exception派生的。
COMException:NET文档建议对任何无法识别的HRESULT抛出COMException,但这不是Windows运行时应用的行为。相反,COMException通常是用于源于组件的未映射异常的标准异常。来自您自己的应用程序代码或系统的未映射异常报告为基本异常,其HResult值不标准。
ExternalException:不包含在.NET for Windows运行时中。对于确实存在的异常(如SEHException),在层次结构中看不到这一点。
关于STATUS_PRIVILEGED_INSTRUCTION(0xC0000096)异常
简介
STATUS_PRIVILEGED_INSTRUCTION---应用程序执行了特权指令,值为0xC0000096。其定义如下:
//
// MessageId: STATUS_PRIVILEGED_INSTRUCTION
//
// MessageText:
//
// {EXCEPTION}
// Privileged instruction.
//
#define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS)0xC0000096L) // winnt
说明
特权指令是一种处理器操作码(汇编指令),它只能在0环模式下执行。这些类型的指令通常用于从windows内核访问I/O设备和受保护的数据结构。常规程序以“用户模式”(环3)执行,这不允许直接访问I/O设备等。原因可能是堆栈损坏或函数指针调用混乱。当使用指向无效数据的函数指针时,通常会发生这种情况。如果您的代码破坏了返回堆栈,也可能发生这种情况。有时追踪这类bug可能相当棘手,因为它们通常很难复制。
异常结构信息
ExceptionAddress: 7bf90000
ExceptionCode: c0000096
ExceptionFlags: 00000000
NumberParameters: 0
源索引和符号服务器
简介
不久前,我必须建立一个符号服务器,带有源索引,那时,关于这个主题的信息不多,所以我很难让所有的东西按照我们想要的方式工作。不幸的是,仍然只有这些相同的信息,但是自从微软将源代码发布到.NET框架并自动将其符号服务器添加到Visual Studio 2010以来,似乎有更多的人意识到了这一点。大多数使用.NET框架的人现在都会意识到,他们可以通过使用Microsoft的符号服务器从Microsoft获取符号文件和源代码来调试框架,但是有多少人真正了解什么是符号服务器,或者Visual Studio如何将源代码获取到.NET框架?答案出人意料地简单,与一些人的看法相反,他们认为这项技术已经存在了似乎是永远的,而且可以供你使用。因此,本文将向您介绍符号服务器的奇迹,也许更重要的是,源索引。
什么是符号服务器?
符号服务器基本上只是一个使用文件系统的非常简单的数据库,用于存储符号文件的不同版本。WinDbg和Visual Studio都可以通过SymSrv DLL使用这些数据库,SymSrv DLL随Windows调试工具包提供,用于为正在调试的应用程序加载匹配的符号。实际上,它不是一个数据库,而是一组结构方便的文件夹和文件,因此,您可以自由地复制和粘贴您的数据库到任何您喜欢的位置,但symbol服务器仍会记录事务,并保留已添加或从数据库中删除的所有内容的记录,因此您不能只是手动添加据我所知的档案。关于symbol服务器的一个重要注意事项是它不支持同时执行多个事务,没有锁定机制来阻止其他人在事务进行时更新数据库,因此您可能需要小心,一次只有一个人在更新数据库。
使用符号服务器意味着每个人都可以轻松访问最新版本的符号,如果需要调试较旧版本的应用程序或库,则无需担心自己会挖不出符号文件,它们将自动加载。
符号服务器本身是非常方便的,因为它允许您在调试时查看调用堆栈和其他有用的信息。但是举例来说,您正在调试一个客户机通过加载一个密钥库而经历的崩溃,并且您机器上的源代码不再匹配用于构建该应用程序特定版本的源代码,您可能很难准确地找到导致崩溃的原因;这是源索引出现的地方。
什么是源索引?
源索引是将命令嵌入到符号文件中的行为,当运行时,将从源代码管理系统中提取源代码的正确版本,或者从您可能已经准备好的其他备份中获取源代码。调试器可以在需要打开文件时运行这些命令,以便获得正确的源文件。因此,当您加载客户端在愤怒的电子邮件中发送给您的小型转储文件时,您可以在Visual Studio中加载它,您将看到用于生成该生成文件的确切源代码,以及(希望)指向有问题的代码行的大箭头所遇到的错误。
如何设置符号服务器
symbol服务器的先决条件是您有一些网络位置来存储数据库,即使您是唯一的用户,它也可以只是硬盘上的一个文件夹。下一步是告诉调试器符号服务器的位置,以便它在调试时检查符号文件。
在最新版本的Visual Studio中,您需要转到“工具”->“选项”->“调试”->“符号”,然后将路径添加到符号服务器。如果符号服务器位于某个网络上,则还应为Visual Studio指定一个本地缓存,以便在下次需要这些符号时将这些符号复制到该网络,而无需从该网络下载这些符号。
在旧版本的Visual Studio中,仅仅指定符号服务器的路径是不够的,还需要告诉它它是符号服务器。您可以将SRV*放在符号服务器路径之前。
SRV*只是symsrv*symsrv.dll*的简写,所以如果您看到完整版本,它的意思完全相同。SRV*语法有几个变体:
SRV*LocalCache*SymbolServerPath SRV*LocalCache*NetworkCache*SymbolServerPath
因此,可以为每个符号服务器指定不同的缓存位置。如果你是从某个非现场位置获取你的符号,你也可以指定一个网络缓存,这样当其他用户需要符号文件时,他们只需要直接从你自己的网络下载,而不是从地球的另一边下载。
如果使用WinDbg,则要添加符号服务器,需要转到“文件”->“符号文件路径”,然后使用上面的SRV*语法添加符号服务器。
您还可以为符号服务器设置一个环境变量,以便Visual Studio和WinDbg(以及任何其他兼容的调试器)都知道您的服务器,而不必在每个应用程序中显式地设置它们。需要创建的环境变量是符号路径,可以在中作为用户或系统变量创建。它对每台服务器使用SRV*语法,如果需要指定多台服务器,则需要用分号分隔每台服务器。
_NT_SYMBOL_PATH= SRV*c:\symbols*\\symbolserver; SRV*c:\symbols*http://www.someotherplace.co.uk/symbols
此时,您应该让调试器在服务器中查找符号,此时该符号可能为空。要向服务器添加符号,需要使用Windows调试工具提供的SymStore.exe。向服务器添加一组符号的基本命令是:
symstore add /f "c:\MyProject\Output\*.*" /s "\\MySymbolServer\Symbols" /t "MyProject" /v "Build 1234" /c "Example Transaction"
关于每个命令的注释:
- add告诉symstore我们正在添加文件。
- /f对于我们要添加的文件(在本例中是一个或多个文件)的路径,如果您像我在这里所做的那样指定一个路径,则它将搜索要添加到服务器的任何兼容文件—这些文件包括Visual Studio生成的调试pdb文件以及二进制文件本身。请记住,如果要从小型转储进行调试,则可能还必须将二进制文件添加到符号服务器。我不知道如何指定要从中添加的多个路径,因此如果您只需要.PDB和.DLL文件(但不需要可执行文件),则必须对每个文件运行单独的命令,或者将要备份的所有文件移动到同一文件夹。
- /s要将文件添加到的符号服务器的路径。如果只是一个空文件夹,那么它将添加必要的文件和文件夹,将空文件夹转换为符号服务器。
- /t事务的名称,这是一个必需的参数,通常您只需将项目名称放在此处,或任何其他标识字符串。
- /v要添加的文件的版本号。它不是必需的,只是为了您的方便,所以如果您需要手动找到一组特定的符号,您可以。
- /c事务的注释,同样地,它不是必需的,只是用于日志文件和您的利益。
Symstore还有一些其他参数,允许您以几种不同的方式设置symbol服务器。我不在这里介绍它们,因为这里有一个很好的MSDN页面来解释它们,您可以从文章底部的链接中找到它们。
如何索引符号文件
在将符号文件添加到服务器之前,可以在其中嵌入命令,以便从版本控制系统或其他任何相关的位置提取当前源代码。Windows调试工具中包含一些脚本,这些脚本将把不同版本控制系统中的源代码索引到PDB文件中。我将给出一个如何使用脚本的快速示例,然后我将检查实际发生的情况,以便如果您有需要,可以编写自己的脚本。
要使用源索引脚本,首先需要安装Perl,因为这些实际上是Perl脚本。一旦您构建了项目,并希望用附加信息为PDB文件编制索引,调试器将需要从版本控制系统中提取源代码,您需要转到Windows安装调试工具中的srcsrv文件夹,并找到版本控制的相关脚本,例如,您正在使用Subversion,那么您需要运行svnindex.cmd。有两个参数需要传递给脚本,以便脚本可以索引文件,它们是指向项目工作目录的源路径的分号分隔列表,以及PDB文件所在文件夹的分号分隔列表。所以你的命令是:
svnindex.cmd /source="c:\SharedModules;C:\MyVeryImportantProject" /symbols="c:\SharedModules\Release;c:\MyVeryImportantProject\Release"
然后,脚本将插入PDB文件中列出的每个文件的命令,以从SVN中提取这些命令。在SVN的情况下,如果需要使用特定的用户名和密码,还可以传入/user=“MyUserName”/pass=“MyPassword”注意,这些参数是特定于SVN脚本的,其他脚本可能不总是接受用户名和密码,并且可能有自己的特定设置。与控制台中的大多数内容一样,您可以通过传递-?作为论据。
每个索引脚本还支持从两个环境变量加载一个变量以及一个名为SrcSrv.ini的配置文件。运行脚本时,它们将使用大多数本地设置,因此命令行参数将覆盖srcsrv.ini,后者将覆盖环境变量。还可以通过添加/ini=“Path to ini file”指定运行脚本时要使用的特定配置文件。
脚本里做了什么
基本上,索引脚本的目的是生成这样的数据块:
SRCSRV: ini ------------------------------------------------ VERSION=1 INDEXVERSION=2 VERCTRL=Test DATETIME=Mon, 04 October 2010 SRCSRV: variables ------------------------------------------ SRCSRVTRG=%targ%\%var4%\%var2%\%fnfile%(%var1%) SRCSRVCMD=cmd /c copy "%var1%" "%SRCSRVTRG%" SRCSRV: source files --------------------------------------- D:\Documents\SKProjects\AlphaForms\AlphaForms\LayeredWindow.cs*11*_*AlphaForms\AlphaForms *svn://192.168.1.5/AlphaForms/trunk/AlphaForms/LayeredWindow.cs SRCSRV: end ------------------------------------------------
上面有一些关于如何构建命令的信息,下面列出了每个文件的该命令的参数。因此,如果该命令是一个简单的副本,那么您可以将该命令设置为:
copy "%var1%" "%srcsrvtrg%
var1引用变量列表中的第一项,在本例中为D:\ Documents\SKProjects\AlphaForms\AlphaForms\LayeredWindow.cs。srcsrvtrg是数据块头中指定文件复制位置的命名变量之一。在调用命令之前,调试器将检查文件是否存在,因此,如果您在此之前打开了该文件的版本,则不需要重新运行一个可能非常慢的命令。srcsrvtrg由其他几个命名变量组成。targ是文件将放入的本地缓存目录,fnfile实际上是一个函数,它从以下括号中指定的路径(在本例中是var1,文件的路径)获取文件名。
您可能已经注意到,两个模符号之间的所有内容都被视为变量,并将被它们表示的实际数据替换(如果可能的话),这种替换值的操作也是递归的,就像srcsrvtrg变量将被它表示的字符串替换一样,然后填写变量targ和var1。
事实上,将这些数据插入PDB文件是完全无用的,因为它只会将您系统中已有的文件复制到其他地方。一个更现实的例子是:
SRCSRV: ini ------------------------------------------------ VERSION=1 INDEXVERSION=2 VERCTRL=Subversion DATETIME=Mon, 04 October 2010 SRCSRV: variables ------------------------------------------ SRCSRVTRG=%targ%\%var4%\%var2%\%fnfile%(%var1%) SRCSRVCMD=cmd /c "svn cat "%var5%@%var2% --non-interactive > "%SRCSRVTRG%" SRCSRV: source files --------------------------------------- D:\Documents\SKProjects\AlphaForms\AlphaForms\LayeredWindow.cs*11*_*AlphaForms\AlphaForms *svn://192.168.1.5/AlphaForms/trunk/AlphaForms/LayeredWindow.cs D:\Documents\SKProjects\AlphaForms\AlphaForms\AlphaForm_WndProc.cs*10*_ *AlphaForms\AlphaForms*svn://192.168.1.5/AlphaForms/trunk/AlphaForms/AlphaForm_WndProc.cs D:\Documents\SKProjects\AlphaForms\AlphaForms\AlphaForm.cs*10*_ *AlphaForms\AlphaForms*svn://192.168.1.5/AlphaForms/trunk/AlphaForms/AlphaForm.cs SRCSRV: end ------------------------------------------------
然后,实际的命令将由main部分中指定的变量生成,因此对于第一个文件,它将如下所示:
cmd /c "svn cat " svn://192.168.1.5/AlphaForms/trunk/AlphaForms/LayeredWindow.cs@11 --non-interactive > "C:\Documents…"
然后将执行此命令,并希望将所需的文件放在目标目录中,然后调试器将尝试打开它。
如果您确实想编写自己的脚本或程序来索引PDB文件,那么您只需要生成一个类似的数据块,然后使用pdbstr.exe将其插入PDB文件。将自己的源代码编制索引的基本步骤将是这样的:
- 收集工作目录中的文件列表
- 获取提取命令的每个文件的参数列表
- 使用srctool获取PDB中引用的文件列表
- 将数据块的头写入某个临时文件
- 对于PDB中的每个文件,将参数添加到临时文件
- 使用pdbstr将数据插入PDB
要获取PDB中引用的文件列表,请使用:
srctool.exe "path to pdb file" –r
它将把pdb中的每个文件打印到一个新的行上。要将数据块添加到PDB文件,需要使用:
pdbstr –w –p:"path to pdb file" –s:srcsrv –i:"path to temp file"
-w开关指定您正在写入文件,使用-r会将数据流(如果存在)打印到控制台。-s给出了我们要写入的数据流的名称,在本例中是srcsrv。实际上,您可以使用任何喜欢的流名称将任何需要的内容插入到PDB文件中,但是Visual Studio将在srcsrv流中查找数据。-我给出了将插入PDB文件的输入文件的路径,在您的情况下,该文件就是您将数据写入的文件。
关于异常RPC_NT_INVALID_STRING_BINDING(0xC0020001)
简介
RPC_NT_INVALID_STRING_BINDING即无效的字符串绑定,值为0xC0020001。其定义如下:
/
// MessageId: RPC_NT_INVALID_STRING_BINDING
//
// MessageText:
//
// The string binding is invalid.
//
#define RPC_NT_INVALID_STRING_BINDING ((NTSTATUS)0xC0020001L)
说明
默认情况下,作为DLL创建的C++项目的托管扩展不链接到诸如C/C++运行库(CRT)库、ATL或MFC的本地C/C++库,不使用任何静态变量。此外,项目设置还指定应在启用/NOENTRY选项的情况下链接DLL。这样做是因为与入口点的链接会导致托管代码在DllMain期间运行,这是不安全的。没有入口点的DLL无法初始化静态变量,除非是非常简单的类型,例如整数。通常在/NOENTRY DLL中没有静态变量。ATL、MFC和CRT库都依赖于静态变量,因此如果不首先进行修改,也不能从这些DLL中使用这些库。如果混合模式DLL需要使用依赖于静态的静态或库(如ATL、MFC或CRT),则必须修改DLL,以便手动初始化静态。手动初始化的第一步是确保禁用自动初始化代码,这对于混合DLL是不安全的,并且可能导致死锁。要禁用初始化代码,请执行以下步骤。
某些DLL不与本机库链接,因此它们的DllMain不会初始化一些所需的本机子系统(如CRT或ATL)。一种推荐的解决方案是从托管DLL中删除入口点:
删除托管DLL的入口点
- 与/ NOENTRY联系。在解决方案资源管理器中,右键单击该项目
单击节点,单击属性。在“属性页”对话框中,单击“确定”
链接器,单击命令行,然后将此开关添加到
附加选项字段。 - 链接msvcrt.lib。在“属性页”对话框中,单击“链接器”,
单击输入。,然后将msvcrt.lib添加到其他依赖项
属性。 - 删除nochkclr.obj。在“输入”页面(与上一步骤相同的页面)中,从“附加依赖项”属性中删除nochkclr.obj。
- CRT中的链接。在“输入”页面(与上一步骤相同的页面)中,将__DllMainCRTStartup @ 12添加到“强制符号引用”属性中。
异常结构信息
ExceptionAddress: 775d4402 (KERNELBASE!RaiseException+0x00000062)
ExceptionCode: c0020001
ExceptionFlags: 00000001
NumberParameters: 1
Parameter[0]: 8007042b//真实错误码或进程退出码