Cannot find or open the PDB file
即找不到pdb文件,因此无法调试。
?
在visual里找到pdb相关的配置选项,共2个如下:
?
configuration property->c/c++->output files->program database file name
?
这是编译时产生的pdb文件的输出位置,vs在编译后会将该位置符合$(TargetName).pdb格式的文件复制到configuration property->general的output directory目录中(不知道是哪里的设置起作用),作为运行时debug信息。不过这一pdb文件包含的信息包括类型信息,但不包括函数定义等符号信息。因此,即使每个源文件都包含公共头文件(如
?
?
configuration property->linker->debugging->generate program database file
?
这是链接时链接器产生的pdb文件的输出位置,它包含项目的 EXE 文件的调试信息。该 文件包含完整的调试信息(包括函数原型),而不仅仅是在 上一个.PDB 中找到的类型信息。
这两个 PDB 文件都允许增量更新。链接器还在其创建的 .exe 或 .dll 文件中嵌入 .pdb 文件的路径。
?
对照项目配置,很快发现问题所在。output files->program database file name里设置的文件名符合$(TargetName).pdb的格式,因此被复制到output directory目录中,而linker->debugging->generate program database file设置的文件名也刚好是这个位置,因此就没有被复制进来,所以“鹊巢鸠占”引起的后果是,包含完整调试信息的9mb大的pdb文件没有被如约创建,而1mb大的pdb文件被错误的复制倒了不该放的地方,自然.exe文件就找不到debug信息了。
?
?
以下作为参考:
?
?? ? ? ? ?
? ?VISUAL c+中的pdb文件及其作用
? ? ?程序数据库 (PDB) 文件保存着调试和项目状态信息,使用这些信息可以对程序的调试配置进行增量链接。当以 /ZI 或 /Zi(用于 C/C++)生成时,将创建一个 PDB 文件。
? ? ?在 Visual C++ 中,/Fd 选项用于命名由编译器创建的 PDB 文件。当使用向导在 Visual Studio 中创建项目时,/Fd 选项被设置为创建一个名为 project.PDB 的 PDB。
? ? 如果使用生成文件创建 C/C++ 应用程序,并指定 /ZI 或 /Zi 而不指定 /Fd 时,则最终将生成两个 PDB 文件:?
VC80.PDB (更笼统地说就是 VCx0.PDB,其中 x 表示 Visual C++ 的版本。)该文件存储各个 OBJ 文件的所有调试信息并与项目生成文件驻留在同一个目录中。
project.PDB 该文件存储 .exe 文件的所有调试信息。对于本机 C/C++代码,它驻留在 /debug 子目录中。对于托管代码,它驻留在 /WINDEBUG 子目录中。
每当创建 OBJ 文件时,C/C++ 编译器都将调试信息合并到 VCx0.PDB 中。插入的信息包括类型信息,但不包括函数定义等符号信息。因此,即使每个源文件都包含公共头文件(如
链接器将创建 project.PDB,它包含项目的 EXE 文件的调试信息。project.PDB 文件包含完整的调试信息(包括函数原型),而不仅仅是在 VCx0.PDB 中找到的类型信息。这两个 PDB 文件都允许增量更新。链接器还在其创建的 .exe 或 .dll 文件中嵌入 .pdb 文件的路径。
Visual Studio 调试器使用 EXE 或 DLL 文件中的 PDB 路径查找 project.PDB 文件。如果调试器在该位置无法找到 PDB 文件或者如果路径无效(例如,如果项目被移动到了另一台计算机上),调试器将搜索包含 EXE 的路径,即在“选项”对话框(“调试”文件夹,“符号”节点)中指定的符号路径。调试器不会加载与所调试的二进制不匹配的 PDB。
通常我们自己封装dll,然后给某个exe文件调用。但是当我们代码写完了之后,想知道我们的dll有没有问题,这个时候在执行的时候就需要进入到我们的dll源代码里面去。正确的做法就是:先将我们的调试目录以及可执行文件配置好,如下图: 命令:添加我们需要调试的可执行程序名字(进入方法:项目名称=》属性=》配置属性=》调试=》命令) 工作目录:就是我们即将调试的可执行程序的路径(进入方法与上面一样) 我们现在将调试的程序以及路径配置好了,但是还差一个路径,就是我们自己写的dll的生成路径,我们必须要将我们生成的dll与调试的可执行文件放在同一个目录下调试,这样在调试时,可执行程序在调用我们的dll的时候才会进入到代码内部。我们只需要在接口函数处设置断点,慢慢调试即可。下面截图显示设置生成的dll的路径与调试路径一致: 进入方法:项目名称=》属性=》配置属性=》链接器=》常规=》输出文件。把这个路径设置成和调试路径一致即可。
转自:http://www.hack95.com/hehe6378/article/details/18659471
调试技巧的总结,内容整理自互联网
调试是软件开发周期中的一个很重要的部分,有时很有挑战性,有时候则让程序员迷惑,有时候让程序员发疯,但是。可以肯定的是,对于任何不是太那个微不足道的程序来说,调试是不可避免的。近年来,调试工具的发展已经使得很多调试任务简单省时了。
本文总结了十个调试技巧,当你使用VS的时候可以节省你很多时间。
1. 悬停鼠标查看表达式
调试有时候很有挑战性,当你步入一个函数想看看哪块出错的时候,查看调用栈来想想值是从哪来的。另一些情况下,则需要添加一些监视表达式,或者查看局部变量列表,这通常还是花费一些时间的,但是。如果你把你鼠标指向你感兴趣的一个变量。你会发现事情简单多了。而且,类和结构体可以通过单击展开。这样。你就可以方便快捷的找到你想查看的变量了。
2. 实时改变值 调试器不仅仅是一个分析程序崩溃或是异常结果的工具了,许多bug都可以通过步入新写的函数,检查函数是否如期望的那样运行来预防。有时候你可能会好奇“如果条件为真函数会正确运行吗”大多数情况下,根本不需要改变代码重启挑起,仅仅把鼠标悬停到一个变量上,双击值然后输入一个新值就可以了。。
3.设置下一条语句 一个典型的调试情况就是通过单步跟踪分析为什么一个函数调用失败了。当你发现一个函数调用的另一个函数返回错误的时候你会怎么做?重启调试?有更好的方法。拖动这个黄色的语句标识到你想下一步执行的语句前就可以了。比如你刚才失败的那块,然后步入。简单,不是吗?
4.编辑然后继续 调试一个复杂的程序,或是一个插件的时候,在一个被调用很多次的函数处发现一个错误。但是不想浪费时间停下来,重新编译然后重新调试。没问题,仅仅在该处改正代码然后继续单步就可以。VS会修正程序然后继续调试不需要重启
注意,编辑然后继续有大量的已知限制,首先,64位代码是不行的。如果他如果为你的C#程序工作。就去工程设置的生成选项,然后目标平台为x86.不要担心。发布版的目标平台和调试的时候是分开的。可以被设置为任何平台。。
第二.编辑然后继续改变在一个方法里应该是局部的。。如果你改变了方法签名,添加一些新方法或是类。你就不得不重启程序了。或者撤销改变来继续。改变方法也包含lambda表达式隐式修改的自动生成的代理类,因此也不能继续。
5.方便的监视窗口 大概现代的调试器都有一个监视窗口,无论如何。VS允许你简单的添加或移除变量。单击空行,输入你的表达式按下回车,或者是在不需要的表达式上按下Delete键就可以删除了。 而且。从监视窗口你不仅仅可以看到“正常”的变量。你可以输入$handles 来追踪你的程序打开了多少句柄(可以方便的修复内存泄漏) ,输入$err 可以看到上一个函数的错误码,然后使用工具-错误信息可以看到更详细的描述,或者输入@eax(64位是@rax)来查看包含函数返回值的寄存器。
6.带注释的反汇编 使用交互式的反汇编模式可以使得优化程序的关键部分变得很容易,VS给出对应你代码每一行的汇编指令,并且运行单步运行。同时,可以在任何位置设置断点。而且,表达式的查看和修改也像在C++代码里一样
7.带有栈的线程窗口 调试多线程的程序是痛苦的。。或者也可以是很有趣的。取决于你的调试器。VS2010真正优美的特性是线程窗口的栈视图,通过窗口的调用栈你可以方便的总览线程。
8.条件断点 如果你尝试通过断点再现一个罕见的事件,该情况引发了一些严重的错误。你可以添加条件断点。定义一个断点的条件,然后如果条件不成立,VS会忽略该断点
9.内存窗口 有些bug由不正确的结构体定义引起,忽略的对齐属性等等。查看内存中的内容可以定位然后修复bug。VS提供了一个放百年的内存窗口,可以把值以8/16/32/64位的形式展示。还有浮点值。也允许实时改变他们。就像在文本编辑器里一样。
10.转到定义 这个特性不是直接关于调试的,而是关于浏览大项目的。如果你尝试找到一些不是你自己写的代码中的错误,快速知道“这个类型是什么”或者“这个函数是干嘛的”,可以节省很多时间,VS通过一个转到定义命令方便了你。
11.命令窗口 第十一的技巧chaau已经建议过了。确实可以节省很多时间,VS支持命令窗口,可以通过,视图-其他窗口-命令窗口来启动。一旦激活,你可以输入不同的命令来自动化调试。举个例子。你可以通过如下命令 简单的模拟MFC COleDateTime 变量。
1
?
dt
.
Format
(
"%Y-%m-%d %H:%M:%S"
)
许可 本文包括源代码和文件在CPOL下授权
----------------------------------------------------------------------------------------------------------------------------------------
[原文发表地址]:Debugging Tips with Visual Studio 2010
[原文发表时间]:2010/8/19 10:48 AM
今天的博文包含了一些有用的能用于VS的调试技巧。 我的朋友Scott Cate(他写了很多很好的关于VS使用技巧和窍门的博客)最近向我强调了这些很好的技巧,大部分使用VS的开发人员好像不知道这些技巧(即使他们大部分都在产品开发组呆过一阵子)。 如果你还没有使用过这些技巧,希望这篇博文能帮你发现它们。 它们学起来很容易,能帮你节省很多时间。
运行到光标(Ctrl+ F10)
我经常看见人们是这样来调试应用程序的: 他们在应用程序需要调试的代码前设置一个断点,然后反复的敲F10/F11来逐步通过代码,直到到达他们真正想要研究的确切位置。有些时候他们需要仔细观察所跨过的每行代码,这样使用F10/F11 就很合理。 但是更普遍的是,他们只想快点进入他们真正关心的那行代码——这是使用F10/F11 就不是最好的选择了。
相反, 你可能想利用调试器支持的特性“运行到光标”。 只需简单地把你的光标放在代码中你想程序运行到的那一行,然后同时敲Ctrl+F10。这样程序就会运行到光标所在的那一行, 然后执行中止,由调试器控制——这样就节约了你反复敲击F10/F11到达那里的时间。即使你想运行到的那行代码不在当前调试的方法或类里,而是在一个独立的方法或类里,这也同样奏效。
条件断点
我们经常在可用性学习中见到另一个普遍的技巧:开发人员设置断点,运行程序,试着输入一些数据,当到达一个断点时,手工检查某种条件是不是成立,如果成立才决定进一步研究。 如果条件不符合他们想要的, 按F5继续执行程序,尝试另外一些输入,再手工重复同样的过程。
VS的条件断点功能提供了一个更加容易的方法来处理以上情况。 条件断点允许你只在某种明确指定的条件成立时才中止执行,由调试器控制。这帮你免于手动检查/恢复你的程序, 使得整个调试过程免去许多手工活,也不那么冗长乏味。
设置一个条件断点
设置一个条件断点十分简单,在代码里按F9为某一行设置一个断点:
然后右击断点——编辑器左边的红色圆圈,在右键菜单中,选择“条件…” :
将弹出以下对话框, 允许你指明某种条件,只有当这种条件成立时,断点才能达到。 例如:我们可以通过写下面的表达式来指明,只有当paginatedDinners列表元素的个数小于10时,才中止程序,由调试器控制。
现在, 当我重新运行程序来研究一下, 调试器只在这个查找返回值小于10时,才中止程序执行。 如果返回值不小于10 ,将不会触发断点。
命中次数功能
有时你只想在条件第N次成立时中止执行。例如:仅当第5次出现查找返回值小于10时,才中止执行。你这样启用这个功能:右击断点, 选择“命中次数…”菜单命令。
将弹出以下对话框, 允许你指明程序中断的条件:条件被第N次满足时,或者条件被满足的次数是N的倍数时,或者条件被满足的次数大于等于N次时。
机器/线程/进程筛选器
你可以右击断点,选择“筛选器…”菜单命令, 来指明断点只在某台特定的机器,或某个特定的进程或线程中才能被触发。
跟踪点——当击中断点时自定义行为
很多人不知道的一个调试功能是使用跟踪点。 跟踪点是一个断点, 当它被击中时,某种自定义的宏会被触发执行。当你想研究你的应用程序而又不想中止执行程序时, 这个功能特别有用。
我将用一个简单的控制台程序来演示如何使用跟踪点。 下面是斐波那契数列的递归实现:
在上面的应用程序中,针对特定的输入,我们使用Console.WriteLine()来输出最后的斐波那契数列。假如我们想在调试过程中研究斐波那契的递归过程——而不停止调试的执行? 跟踪点能帮我们很轻松地做到这一点。
设置跟踪点
你可以这样启用跟踪点:按F9在代码上设置一个断点, 右击断点,在右键菜单中选择“命中条件…”菜单命令:
将弹出以下对话框——允许你指定当断点触发时,进行何种操作:
如上所示,我们指定每次当断点的条件成立时,打印跟踪信息。注意我们指定了想要输出的局部变量“X” 的值作为输出信息的一部分。 局部变量能通过{变量名}的语法被引用。 也有内嵌的命令(像$CALLER,$CALLSTACK, $FUNCTION等等)可以用来输出跟踪信息中常见的值。
上面对话框的底部, 我们也选中了“继续执行”单选框——表示我们不希望调试器暂停程序。 相反,程序会继续执行——只是我们自定义的跟踪信息会在每次断点条件满足时输出,就这点不同。
现在当我们运行程序时,我们会发现自定义的跟踪信息会自动出现在VS的输出窗口中——使我们能看到程序的递归过程。
你也可以选择为你的程序设置一个自定义跟踪监听器——这样跟踪点的输出信息就会被重定向到它里面,而不是VS的输出窗口里。
跟踪点——运行自定义的宏
上周我在伦敦做了一次演讲, 听众中有个人问了这样一个问题:有没有可能当击中一个跟踪点时,自动输出所有的局部变量。
这个功能不是内置在VS中的, 但是可以通过在VS中写一个自定义的宏来启用它,然后设置一个跟踪点,当它被击中时,调用这个宏。 为了实现这个目的, 打开VS中的宏窗口(工具->宏->宏菜单命令)。然后在项目管理器“MyMacros”结点下面, 选择模板或者新建一个模板(如:添加一个名为“UsefulThings”的 模板), 再将下面的VB宏代码贴到模板里,并保存它:
Sub DumpLocals()
Dim outputWindow As EnvDTE.OutputWindow
??????? outputWindow = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput).Object
Dim currentStackFrame As EnvDTE.StackFrame
??????? currentStackFrame = DTE.Debugger.CurrentStackFrame
??????? outputWindow.ActivePane.OutputString("*Dumping Local Variables*" + vbCrLf)
For Each exp As EnvDTE.Expression In currentStackFrame.Locals
??????????? outputWindow.ActivePane.OutputString(exp.Name + " = " + exp.Value.ToString() + vbCrLf)
Next
End Sub
上面的宏代码依次检测当前堆栈,获取所有的局部变量,并将其显示在输出窗口。
使用DumpLocals自定义宏
在下面这个简单的应用程序中,我们可以利用自定义的“DumpLocals”宏:
在上面的Add方法的return语句上,按F9设置一个断点。 右击断点,选择“命中条件…”菜单命令:
将弹出以下对话框,上例中,我们选中了“打印信息”的单选框,再手工指定希望输出的变量, 而这里, 我们选中“运行宏”的单选框,使它指向我们创建的自定义宏UsefulThings.DumpLocals:
我们仍然选中“继续执行”单选框,这样能保证当跟踪点被击中时,程序依然能够继续执行。
运行程序
现在当我们按F5运行程序,当调用Add方法时,我们将看见以下输出出现在VS输出窗口中。 注意当跟踪点被击中时,宏是如何自动列出各个变量名及其值的。
总结
VS调试器功能非常丰富。 我强烈建议大家抽出一些时间来学习它的所有功能。 以上的技巧和诀窍只是很多大家没有真正意识到的功能中的一小部分。
我之前写过其他一些关于VS2010调试器改进的博客(包括数据标签固定,断点导入导出,保留最后值变量, 等等)。 我将发表更多关于VS2010的智能跟踪和转储文件调试支持的博文。这些技术提供了很多非常酷的新功能,会让程序(包括产品中的程序)的调试变得非常简单和强大。
也请务必看看Scott Cate很棒的VS2010技巧和诀窍系列,你可以学习如何更好的利用VS。他有一些非常棒的免费视频和博客。
也要看看Jim Griesmer很棒的VS调试技巧和诀窍系列。 他有许多很好的可以利用的技巧和诀窍。
希望这能对您有所帮助。