您的位置:首页 > 编程语言

VS中调试时不能关联源代码问题

2016-01-04 09:52 519 查看
转自:'target='_blank'>http://blog.csdn.net/hydream/article/details/7241439
/*****************************************************************/

/**本人原创文章,转摘请保留本段内容,万分感谢!
/**microdreamsoft(LinShaohua):
/**由于本人水平有限,欢迎各位高手指正。
/**本人所有原创文章将发布在以下blog:
/**http://blog.csdn.net/hydream/**http://websoso.bokee.com/**http://89727175.qzone.qq.com/**http://hi.baidu.com/microdreamsoft/**http://751728871.qzone.qq.com/*****************************************************************/

一、问题提出:

我们有时候调试程序的时候,会碰到一种问题,例如通过myclass.cs编译后的程序,我们在调试的时候,却发现即使我们有myclass.cs源文件,VisualStudio却不能自动关联,当你在堆栈窗口双击打开时候,会出现类似以下的界面:



(图1)

提示没有源代码,有时候还会弹出对话框,让你选择源文件。尤其是在调试第三方代码,或者是调试在其他机子上编译的程序时候,会出现这种情况,那么问题在哪里呢?

二、VS中是怎样查找源文件的?

要弄清楚这个问题,首先要理解pdb文件的作用,关于这个文件的知识,请见文后的《pdb文件知识》。

源文件和可执行模块(exeordll)是通过pdb文件进行关联的。如下图所示:



可执行模块中保存有pdb文件的信息,pdb文件中保存有源文件的信息。



VS查找源文件的流程是这样的:

1、根据可执行模块中保存的pdb文件信息(guid,pdb文件名,age)查找加载pdb文件。

2、根据pdb中的源文件路径查找源文件。如果源文件在路径中不存在,则在“图1”中的“Browsetofindsource”可以使用,点击后会弹出文件打开对话框。如果pdb是publicpdb文件,则没有包含源文件信息,这时“图1”中的“Browse
tofindsource”变成灰色,不可使用。

三、解决问题的思路方法

有了这个流程概念后,我们就可以知道,如果无法关联源文件或者无法关联正确的文件的话,出的问题一定在pdb上。

那么我们怎么来查找问题呢?

1、首先确定vs是能找到pdb文件,这个可以在vs的模块列表窗口和堆栈窗口中看到。选中相应的模块,然后点击右键,在弹出的菜单中选择“SymbolLoadInformation”,可以看到pdb文件的加载信息。例如:

E:\temp\WindowsFormsApplication2\WindowsFormsApplication2\bin\Debug\WindowsFormsApplication2.pdb:Symbolsloaded.

在“模块列表窗口”中可以看到最终加载的符号文件信息。



其中SymbolStatus是符号文件加载状态。SymbolFile是加载的符号文件的全路径信息。

2、如果vs不能加载正确的pdb文件,则“堆栈窗口”中的对应模块会变成灰色。如果是不能正确加载pdb文件,则有两种情况。

1)pdb文件不在vs搜索的路径之内。

这种情况发生在pdb文件丢失,或者pdb文件拷贝到其它目录了。这个可以通过“SymbolLoadInformation”窗口看到。

2)pdb文件不匹配。

这种情况就比较难发现一点,因为很多人以为pdb文件的关联是通过文件名的。例如明明在可执行模块的同目录下,有同文件名的pdb文件,却没有加载,这是怎么回事呢?

这个就要看看这个pdb文件的签名是否和exe或者dll中保存的pdb文件一直。

我们可以通过dumpbin/headers命令查看可执行模块中保存的pdb文件信息。例如:

Microsoft(R)COFF/PEDumperVersion10.00.40219.01

Copyright(C)MicrosoftCorporation.Allrightsreserved.

DumpoffileSystem.Windows.Forms.dll

PEsignaturefound

FileType:DLL

FILEHEADERVALUES

14Cmachine(x86)

3numberofsections

4D8C1991timedatestampFriMar2512:26:572011

0filepointertosymboltable

0numberofsymbols

E0sizeofoptionalheader

210Echaracteristics

Executable

Linenumbersstripped

Symbolsstripped

32bitwordmachine

DLL

OPTIONALHEADERVALUES

10Bmagic#(PE32)

8.00linkerversion

47B000sizeofcode

4F000sizeofinitializeddata

0sizeofuninitializeddata

47C17Eentrypoint(7B44C17E)

2000baseofcode

47E000baseofdata

7AFD0000imagebase(7AFD0000to7B49DFFF)

2000sectionalignment

1000filealignment

4.00operatingsystemversion

0.00imageversion

4.00subsystemversion

0Win32version

4CE000sizeofimage

1000sizeofheaders

4CBAAAchecksum

3subsystem(WindowsCUI)

400DLLcharacteristics

Nostructuredexceptionhandler

100000sizeofstackreserve

1000sizeofstackcommit

100000sizeofheapreserve

1000sizeofheapcommit

0loaderflags

10numberofdirectories

0[0]RVA[size]ofExportDirectory

47C124[57]RVA[size]ofImportDirectory

47E000[4D6E0]RVA[size]ofResourceDirectory

0[0]RVA[size]ofExceptionDirectory

0[0]RVA[size]ofCertificatesDirectory

4CC000[C]RVA[size]ofBaseRelocationDirectory

47C0A8[1C]RVA[size]ofDebugDirectory

0[0]RVA[size]ofArchitectureDirectory

0[0]RVA[size]ofGlobalPointerDirectory

0[0]RVA[size]ofThreadStorageDirectory

0[0]RVA[size]ofLoadConfigurationDirectory

0[0]RVA[size]ofBoundImportDirectory

2000[8]RVA[size]ofImportAddressTableDirectory

0[0]RVA[size]ofDelayImportDirectory

2008[48]RVA[size]ofCOMDescriptorDirectory

0[0]RVA[size]ofReservedDirectory

SECTIONHEADER#1

.textname

47A184virtualsize

2000virtualaddress(7AFD2000to7B44C183)

47B000sizeofrawdata

1000filepointertorawdata(00001000to0047BFFF)

0filepointertorelocationtable

0filepointertolinenumbers

0numberofrelocations

0numberoflinenumbers

60000020flags

Code

ExecuteRead

DebugDirectories

TimeTypeSizeRVAPointer

--------------------------------------

4D8C1991cv310047C0C447B0C4Format:RSDS,{99F11F8D-84DA-4309-8DA9-2B4BE6DE8672},1,System.Windows.Forms.pdb

SECTIONHEADER#2

.rsrcname

4D6E0virtualsize

47E000virtualaddress(7B44E000to7B49B6DF)

4E000sizeofrawdata

47C000filepointertorawdata(0047C000to004C9FFF)

0filepointertorelocationtable

0filepointertolinenumbers

0numberofrelocations

0numberoflinenumbers

40000040flags

InitializedData

ReadOnly

SECTIONHEADER#3

.relocname

Cvirtualsize

4CC000virtualaddress(7B49C000to7B49C00B)

1000sizeofrawdata

4CA000filepointertorawdata(004CA000to004CAFFF)

0filepointertorelocationtable

0filepointertolinenumbers

0numberofrelocations

0numberoflinenumbers

42000040flags

InitializedData

Discardable

ReadOnly

Summary

2000.reloc

4E000.rsrc

47C000.text

注意上面的加粗信息。

Format:RSDS,{99F11F8D-84DA-4309-8DA9-2B4BE6DE8672},1,System.Windows.Forms.pdb

Format:RSDS:pdb文件的格式。

{99F11F8D-84DA-4309-8DA9-2B4BE6DE8672}:关联的pdb文件tag。

1:关联的pdb文件的age。

System.Windows.Forms.pdb:关联的pdb文件的文件名。

Vs加载pdb文件的时候会严格验证guid和age必须一直,即使文件名相同也不行。

所以如果我们碰到同名的pdb文件不能加载,我们可以再看看pdb文件的信息,看看是否一致。

3、如果能加载正确的pdb文件了,却不能自动关联对正确的源文件。这时候就可以看看pdb文件中对应的源文件信息是否正确。

查看pdb文件的工具,我们可以使用vs安装目录下的MicrosoftVisualStudio10.0\DIASDK\Samples\DIA2Dump中的DIA2Dump工具。这个有源代码,需要我们重新编译就可以使用了。

Dia2dumppdb文件名>>结果文件

打开结果文件,我们就可以看到里面包含的各种信息,例如源文件信息。



Compiland就是编译的单元,我们可以看到全路径信息。然后到对应的路径下查看是否源代码文件是否存在。

四、注意
另外值得提一下的是,在.net中,在编译的时候必须要采用/debug:full指令,而不是/debug:pdbonly,如果是后者,也是可以生成pdb文件,但是还是不能进行源代码级别的调试的,原因是/debug:pdbonly虽然和/debug:full一样生成同样的pdb文件,它们的唯一区别是后者会在assembly中加上:DebuggableAttribute。原因是.net是虚拟机执行的,这个标记的作用是告诉.netjit要保留调试信息,否则经过jit编译后的机器码就和pdb中的调试信息无法关联了。C/c++不存在这个问题。

详细请参见:http://msdn.microsoft.com/en-us/library/8cw0bt21.aspx



<pdb文件知识>:


Pdb文件是programdatabase的缩写,意思为程序数据库。它从编译器的角度描述了一个程序的组成,例如源代码,函数,变量,行号等信息。


具体可以参考以下资料:

1、《软件调试》(张银奎编著)

2、《HowtoInspecttheContentofaProgramDatabase(PDB)File》http://www.codeproject.com/Articles/37456/How-To-Inspect-the-Content-of-a-Program-Database-P

3、《PDBFiles:WhatEveryDeveloperMustKnow》http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/05/11/pdb-files-what-every-developer-must-know.aspx

4、MSDN上的信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: