PDB文件:每个开发人员都必须知道的

PDB Files: What Every Developer Must Know
http://www.wintellect.com/CS/blogs/jrobbins/archive/2009/05/11/pdb-files-what-every-developer-must-know.aspx
 
一 什么是PDB文件

大部分的开发人员应该都知道PDB文件是用来帮助软件的调试的。但是它究竟是如何工作的呢?我们可能并不清楚。本文描述了PDB文件的存储和内容。同时还描述了debugger如何找到binay相应的PDB文件,以及debugger如何找到与binay对应的源代码文件。本文适用于所有的Native和 Managed的开发人员。

在开始前,我们先定义两个术语:private build,用来表示在开发人员自己机器上生成的build;public build,表示在公用的build机器上生成的build。private build相对来说比较简单,因为PDB和binay在相同的地方,通常我们遇到的问题都是关于public的。 
 
所有的的开发人员需要知道的最重要的事情是“PDB文件跟源代码同样的重要”, 没有PDB文件,你甚至不能debugging。对于public build,需要symbol server存储所有的PDB,然后当用户报告错误的时候,debugger才可以自动地找到binay相应的PDB文件, visual studio 和 windbg都知道如何访问symbol server。在将PDB和binay存储到symbol server前,还需要对PDB运行进行source indexing, source indexing的作用是将PDB和source关联起来。 
 
接下来的部分假设有已经设置好了symbol server和source server indexing。TFS2010中可以很简单地完成对一个新的build的source indexing 和 symbol server copying。
 

二 PDB文件的内容

PDB不是公开的文件格式,但是Microsoft提供了API来帮助从PDB中获取数据。
 
Native C++ PDB包含了如下的信息:
 * public,private 和static函数地址;
 * 全局变量的名字和地址;
 * 参数和局部变量的名字和在堆栈的偏移量;
 * class,structure 和数据的类型定义;
 * Frame Pointer Omission 数据,用来在x86上的native堆栈的遍历;
 * 源代码文件的名字和行数;
 
.NET PDB只包含了2部分信息:
 * 源代码文件名字和行数;
 * 和局部变量的名字;
 * 所有的其他的数据都已经包含在了.NET Metadata中了;  
 

三 PDB如何工作

当你加载一个模块到进程的地址空间的时候,debugger用二中信息来找到相应的PDB文件。第一个毫无疑问就是文件的名字,如果加载 zzz.dll,debugger则查找zzz.pdb文件。在文件名字相同的情况下debugger还通过嵌入到PDB和binay的GUID来确保 PDB和binay的真正的匹配。 所以即使没有任何的代码修改,昨天的binay和今天的PDB是不能匹配的。可以使用dempbin.exe来查看binary的GUID。
 
在VisualStudio中的modules窗口的symbol file列可以查看PDB的load顺序。第一个搜索的路径是binary所在的路径,如果不在binary所在的路径,则查找binary中hardcode记录的build目录,例如obj\debug\*.pdb, 如果以上两个路径都没有找到PDB,则根据symbol server的设置,在本地的symbol server的cache中查找,如果在本地的symbol server的cache中没有对应的PDB,则最后才到远程的symbol server中查找。通过上面的查找顺序我们可以看出为什么public build和private build的PDB查找不会冲突。
 
对于private build有时我们需要在别人的机器上debug的情况,需要将相应的PDB与binary一起拷贝,对于加入GAC的.NET的binary,需要将PDB文件拷贝到C:\Windows\assembly\GAC_MSIL\Example\1.0.0.0__682bc775ff82796a类似的binary所在的目录。另一个变通的方法是定义环境变量DEVPATH,从而代替使用命令GACUTIL将binary放入GAC中。在定义DEVPATH后,只需要将binary和PDB放到DEVPATH的路径,在DEVPATH下的binary相当于在GAC下。使用DEVPATH,首先需要创建目录且对当前build用户有写权限,然后创建环境变量DEVPATH且值为刚才创建的目录,然后在web.config,app.config或machine.config中开启development模式,启动对DEVPATH的使用
<configuration>
   <runtime>
      <developmentMode developerInstallation="true"/>
   </runtime>
</configuration>

在你打开了development模式后,如果DEVPATH没有定义或路径不存在的话会导致程序启动时异常"Invalid value for registry"。而且如果在machine.config中开启DEVPATH的使用会影响其他的所有的程序,所以要慎重使用machine.config。
 
最后开发人员需要知道的是源代码信息是如何存储在PDB文件中的。对于public builds,在运行source indexing tool后,版本控制工具将代码存储到你设置的代码cache中。对于private builds,只是存储了PDB文件的全路径,例如在c:\foo下的源文件mycode.cpp,在pdb文件中存储的路径为c:\foo\mycode.cpp。对于private builds可以使用虚拟盘来增加PDB对绝对路径的依赖,例如可以使用subst.exe将源代码路径挂载为V:,在别人的机器上debug的时候也挂载V:。

 

完!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,我可以为您提供一个简单的Python代码实现方向金字塔分解的每个步骤。 首先,我们需要安装OpenCV和NumPy库: ``` pip install opencv-python pip install numpy ``` 接下来,我们可以按照以下步骤实现方向金字塔分解: 1. 图像金字塔的构建: ```python import cv2 import numpy as np img = cv2.imread('image_path.jpg') pyramid = [img] for i in range(4): img = cv2.pyrDown(img) pyramid.append(img) ``` 这里我们使用了OpenCV提供的pyrDown函数,对原始图像进行了四次降采样,得到了一个包含五个不同分辨率的图像构成的金字塔。 2. 方向分解: ```python def gabor_filter(img, ksize, sigma, theta, lambd, gamma, psi): kernel = cv2.getGaborKernel(ksize, sigma, theta, lambd, gamma, psi) filtered = cv2.filter2D(img, cv2.CV_32F, kernel) return filtered angles = [0, 45, 90, 135] filtered_images = [] for i in range(len(pyramid)): for j in range(len(angles)): filtered = gabor_filter(pyramid[i], (5, 5), 2.0, angles[j], 2*np.pi/3, 1.0, 0.0) filtered_images.append(filtered) ``` 这里我们定义了一个gabor_filter函数,用于对图像进行Gabor滤波,得到不同方向的子图像。然后,我们对每个分辨率的图像和每个方向的角度都进行了Gabor滤波,得到了一个包含20个不同方向的子图像列表。 3. 尺度分解: ```python scaled_images = [] for i in range(len(filtered_images)): img = filtered_images[i] for j in range(4): img = cv2.pyrDown(img) scaled_images.append(img) ``` 这里我们对每个方向的子图像进行了四次降采样,得到了不同尺度的子图像。 4. 金字塔重建: ```python reconstructed_pyramid = [] for i in range(len(pyramid)): imgs = [] for j in range(len(angles)): index = i * len(angles) + j img = scaled_images[index] for k in range(4): img = cv2.pyrUp(img) imgs.append(img) reconstructed = np.sum(imgs, axis=0) reconstructed_pyramid.append(reconstructed) reconstructed_img = reconstructed_pyramid[0] for i in range(1, len(reconstructed_pyramid)): reconstructed_img = cv2.pyrUp(reconstructed_img) reconstructed_img += reconstructed_pyramid[i] cv2.imshow('Image', reconstructed_img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 这里我们首先将每个尺度和方向上的子图像进行了上采样,然后对每个分辨率的图像重建成一个整体图像,最后将不同分辨率的整体图像进行上采样和累加,得到了重建后的原始图像。 这就是一个简单的Python代码实现方向金字塔分解的例子。请注意,这个例子只是一个简单的演示,并不能完美地对图像进行分解和重建,但可以让您更好地理解方向金字塔分解的每个步骤。 ### 回答2: 要复现Python中的每个步骤,需要按照以下方式进行: 1. 安装Python:首先,需要从Python官方网站(https://www.python.org)下载Python的安装程序,并按照提示进行安装。确保选择合适的操作系统和版本。安装完成后,可以在命令行中输入`python --version`来验证是否安装成功。 2. 开发环境的选择:可以选择使用集成开发环境(IDE)或者文本编辑器来编写Python代码。一些常用的IDE包括PyCharm、Anaconda和Jupyter Notebook。文本编辑器方面,可以选择Sublime Text、VS Code或Atom等。根据个人喜好和需求进行选择,并安装相应的软件。 3. 编写代码:使用选择好的开发环境或文本编辑器,创建一个新的Python文件(通常以`.py`为文件后缀)。在文件中编写Python代码,根据需求使用合适的语法和标准库函数。可以使用控制流语句(如if-else、for循环和while循环)实现流程控制,还可以使用Python的内置函数和模块来完成各种任务。 4. 运行代码:在开发环境或文本编辑器中,选择运行Python文件的选项(通常是点击运行按钮或使用快捷键)。代码将会被解释器解析执行,并输出结果。可以根据需要进行代码的调试和修改。 5. 调试和优化:在代码运行过程中,如果遇到错误或异常,可以使用调试工具(如断点调试)来找出问题所在,并进行修复。同时,还可以优化代码的性能,提高效率和可读性。针对不同的需求,可以使用一些优化技巧和模块(如Numpy、PyTorch等)来提升Python代码的执行效率。 总之,要复现Python中的每个步骤,需要安装Python、选择适合的开发环境或文本编辑器、编写代码、运行代码以及进行调试和优化。这些步骤将帮助你使用Python语言进行各种编程任务。 ### 回答3: 复现Python的每个步骤涉及以下几个方面: 1. 安装Python:首先需要下载Python的安装包,并根据操作系统的不同选择对应的版本。然后运行安装程序,按照提示进行安装。 2. 学习Python语法:掌握Python的基本语法是复现每个步骤的前提。可以通过阅读官方文档、参考书籍或者在线教程来学习Python的语法。 3. 编写脚本:根据复现的具体步骤,使用Python编写相应的脚本。脚本可以包含变量定义、条件语句、循环语句等,以实现特定的功能。 4. 导入模块:Python的强大之处在于其丰富的模块库。根据需求,可以使用不同的模块来辅助实现复现的每个步骤。常用的模块包括numpy、pandas、matplotlib等。 5. 运行脚本:使用Python解释器来运行编写的脚本。可以在终端上输入命令行指令,或者通过集成开发环境(IDE)运行脚本。 6. 调试和修改:根据脚本运行的结果,进行调试和修改。可以使用Python提供的调试工具,如pdb,来辅助定位问题并进行修复。 复现每个步骤需要结合具体的场景和需求进行实践。根据实际情况,可能需要查阅文档、参考示例代码,不断尝试和调整代码,直到达到预期的效果。Python的强大和灵活性使其成为许多任务的首选语言,只要掌握了基本的语法和使用方法,就能够进行各种复现操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值