如何将源代码嵌入到pdb中,并让调试器使用它? - c#

注意:我的目标关注点是C#将MLR与常规MSIL作为目标,以防万一,某些情况下可以工作,但在更一般的情况下不起作用。

现有的一些源调试支持示例

最近发布了the Sourcepack project版本,该版本允许用户重写pdb文件中的源路径以指向不同的位置。当您具有程序集的源代码,但又不想尝试将其放入与构建时完全相同的文件系统位置时,这非常有用。

http://lowleveldesign.wordpress.com/2011/08/26/sourcepack-released/

对于开源项目,使用http://www.symbolsource.org/作为简化项目用户获取符号和来源的方法是一个好主意。

问题

但是,在很多项目中,出于法律或便利的原因,使用这种方法不太可行。同样,可能正在调试项目的人员可能相对较小或受限制。

默认情况下,项目的pdb包含指向磁盘上文件(IIRC)的指针,然后源索引可以添加将指针嵌入到源位置的功能(例如,在版本控制系统中),然后使用源服务器实际获取源的指针。

目标

仅将实际源代码放入pdb中(实际上只是取消引用当前写在PDB中的指针),看起来事情可能更简单(对于某些构建,例如debug和/或仅供内部使用)。这样看来,您可以跳过整个源服务器部分(至少在理论上是这样),并消除对调试时故事的一些依赖。是否以压缩形式存储源在很大程度上是正交的,但是为了使现有调试器的实现更简单,第一遍可能不会这样做。

由于PDB匹配二进制的故事已经非常好,因此将源放入PDB甚至比源服务器指针还要好,因为指针可能会随着时间而中断(源控制系统移动或更改为其他系统,或者(无论如何),但PDB中的实际来源是“永远的”。

这与“源服务器”支持有何不同?

(这是在Tigran发表评论并询问会有什么好处之后通过编辑添加的)

可以与之进行比较的“基准”场景是当今使用“正常”源服务器实例的“正常”调试经验。在这种情况下,调试引擎(AFAIK)会从PDB获取一个指针(通过备用流),然后使用已注册的源服务器尝试通过该指针获取源。由于给定的程序集通常将包含多个源文件,因此要么有一个包含基本位置的单个指针,要么在PDB中(或其他东西)有多个指针,但这应与本讨论正交。

对于需要隐藏/不可访问源的项目(例如大多数Microsoft产品,例如Windows,Office,Visual Studio等),则使PDB包含指针比包含实际源要好得多(即使它是加密)。如果没有必要的网络访问权限和权限,此类指针就毫无意义,因此,这种方法意味着您可以将PDB交付给地球上的任何人,而不必担心它们能够访问您的源(最坏的情况是,它们会瞥见您的源如何我想树被安排了)。

但是,有2个大型项目(特别是构建项目)不存在这种“隐藏源代码”的好处。

第一个是只能由仍然有权访问源代码的人使用的版本。在您自己的计算机上完成的构建永远不会离开该计算机是一个很好的例子,因为攻击者无论如何都需要从您的文件系统中读取文件以获取源,因此从一个文件(.cs)到另一个文件(.cs)进行读取。 pdb)在攻击难度/向量方面的差异相对较小。同样,已完成的构建并将其推送到测试/分阶段环境,在此环境中,访问计算机上pdb的人员等于或可以“正常”访问源的人员的一部分。

第二个是(某种程度上显然是)开源项目,无论如何该项目的源代码已经向所有人开放,因此对任何人隐藏源代码都没有好处。

请注意,这可以相对容易地扩展为以加密形式包括源(因为我们已经在谈论必须存储格式/编码数据),但是这样做的复杂性将使这种情况可能不太有用。不仅仅是使用“普通”源服务器。

有好处吗?

撇开上面的描述,允许这样做的潜在好处包括(但不限于:)此刻突然出现的这些好处:

无需处理设置源服务器支持。 It Just Works(IJW),至少在/如果调试器知道要查看pdb的情况下才有效。

同时,您仍然可以做一个“固定”源服务器,它只是一个提取源并将其反馈给调用者的虚拟对象。这样的配置对于每个人都可以是相同的(例如,使用localhost),仍然消除了当前实际配置源服务器的需要

无需构建就包含“源索引”

由于构建始终会读取源文件并写入pdb文件,因此,我们只是在修改pdb中写入的内容,而不会因为进行网络调用或读取内存中尚不存在的数据而受到任何构建时性能的影响。
在“原生”构建支持将源放入之前,这可能是一个简单的构建后步骤,可能首先通过Sourcepack项目的一个小分支来实现
已经完成了读取/修改PDB文件的工作:)

不依赖具有源代码控制系统的团队/项目
不依赖于被检入源控制系统的每个文件的特定版本(大多数人不会检入他们在IDE中执行的每个构建)
无需访问具有该文件的特定源代码管理系统

例如,在DVCS情况下,PDB指针可能是git或mercurial或其他任何“随机”实例,不一定是您有权访问的实例
用来将该版本追溯到您确实有权访问的源控制服务器实例的源服务器工具(如果该版本甚至存在于其中)还不存在AFAIK)

如果项目死亡(被删除)或移动,则没问题

例如,如果项目从以下一项转移到另一项:自托管,sourceforge,github,bitbucket,codeplex,code.google.com等。

如果您正在调试的计算机没有(或不足)网络访问权限,则没有问题

例如,如果您正在将“网络KVM”放入用于调试问题的框中,但是它没有网络,或者它只能与断开连接的网络通信,从而无法访问源控制服务器)。

在极端情况下,具有从构建中恢复某些项目源的能力。 ;)

注意:另一种方法是将源代码包括在实际程序集中(例如,作为资源),但是pdb是一个更好的选择(易于交付没有pdb的版本,如果源代码位于pdb中,则不会产生正常的运行时性能影响因为程序集是相同的代码和相同的大小,等等)

如何执行?

从表面上看,添加这种支持似乎不太困难,但是我觉得这是因为我对所涉及的机制并不了解,而不是说这很简单。实施。 🙂

我的猜测可能是:

添加一个构建后步骤,该步骤将执行与Sourcepack类似的操作,但不更改指针,而是将其替换为实际源。

根据源服务器需要执行的操作,可能需要加上前缀,否则实际源将位于其他备用数据流中,并且“指针”被更新为“ source-in-pdb:ads-foo.cs” ' 管他呢。前缀或指针可以包括源文件的存储方式(未压缩,gzip,bzip2等,以及文件编码)

实现一个“源服务器”,该服务器实际上从有问题的pdb中提取源并将其返回。

源服务器“ API”是否具有足够的信息来获取PDB的位置,更不用说它是否有权读取内容了。

完整性检查?

随着上面的胡言乱语,问题实际上是:

这种东西已经存在了吗? (如果是,请提供指针!)
假设尚不存在,那么上述内容作为首过实施是否有意义?上面有没有陷阱或复杂性?
假设上述内容为“否”和“是”,那么是否有一个现有的项目对此有意义(接近或在其现有范围内)?

参考方案

我已阅读此书,并希望总结一下我的理解以便清楚

今天,调试器使用PDB获取文件和校验和的磁盘路径,这些文件经过编译以创建可执行文件的给定部分。然后,调试器尝试同时使用本地磁盘和可用的符号服务器加载文件。根据该建议,我们只将文件本身嵌入到PDB中就可以跳过中间人。尤里卡,不再寻找源!

作为以这种方式完成了相当一部分挖掘源代码工作的人,我喜欢为您的所有调试需求提供一个软件包的想法。但是,关于此提议有两个方面需要考虑。

首先是将源代码实际嵌入到PDB中。这是非常可行的。 PDB本质上是一个轻量级的文件数据库。它的编码具有结构性,但AFAIK可以将所需的任何内容放入某些插槽(例如,局部变量值/类型)。某些插槽可能有大小限制,但是我敢肯定,您可以发明一种编码方案,将大文件分解为多个块。

第二个方面是让调试器实际从PDB加载文件,而不是在磁盘上搜索文件。我不太熟悉调试器的那部分,但是据我了解,它仅使用2条信息来定位文件

磁盘上文件的路径
所述文件的校验和(用于消除同名文件的歧义)

我相当确定这是传递给符号服务器的唯一信息。这使得实现符号服务器变得不可行,因为它无法访问PDB(假设我当然是对的)。

我挖了希望有一个您可以重写的VS COM组件,它将允许您拦截给定路径的文件的加载,但我找不到。

我认为可行的一种方法是

将源代码嵌入到PDB中
有一个既可以将源提取到已知位置又可以重写PDB以指向该位置的工具。

虽然这不是您想要的。

休眠还是Application Server JPA? - java

我在生产中使用Glassfish,在测试中使用OpenEJB。我正在使用JPA 1.0。我使用的是Hibernate,但没有特定的Hibernate功能,只有标准的JPA。休眠在这个集合中是多余的,应该删除,对吗? java参考方案 OpenEJB和Glassfish均提供JPA实现。因此,要运行您的应用程序,您不需要休眠。但是,在某些特殊情况下,JPA实现…

将SQL Server Serilog接收器包装在Async中是否有意义? - c#

我正在尝试最大程度地减少从.NET Core应用程序将日志写入SQL Server的性能影响。过去,我将Serilog File接收器包装在Async接收器中-这极大地提高了性能。SQL Server sink documentation指出它将定期和/或在达到batchPostingLimit时批处理日志条目。我找不到有关它决定发出INSERT命令时发生的…

数学和科学方程式和Fomulas的数​​据类型-SQL Server 2008? - c#

我正在使用SQL Server2008。我有一个用于教育部门工作的小项目。为此,我需要存储数学和科学方程式和公式。这意味着数据可能包含带有上标和下标的值。我希望以相同的格式保存数据。是否有适合我需求的适当数据类型? 参考方案 如果此列专门用于存储数学方程式和科学公式,那么我将使用Xml列,然后将数据存储在MathML format中。文字段落,例如说明,可以…

使用-source 8或更高版本来启用lambda表达式[重复] - java

This question already has answers here: Specifying java version in maven - differences between properties and compiler plugin (3个答案) 去年关闭。 当我尝试运行Maven构建时遇到构建错误。我创建了一个包含lambda函数的简单J…

如何在pyodbc输出转换器函数中解压缩SQL Server DATETIME? - python

我将输出转换器添加到pyodbc连接对象,以处理从SQL Server返回的日期类型。我能够使用以下命令解压缩datetime.time结构:tuple = struct.unpack("HHHI", dateObj) 效果很好。我无法弄清楚datetime.datetime对象的秘密之处,根据pyodbc文档,它是TIMESTAMP_S…