暴雪暗黑破坏神4从visualstudio调试Linux内核转储

null

暴雪正在使用VisualStudio2019 在WSL上调试Linux内核转储 . 下面这篇博文是由比尔·伦道夫写的,他是暴雪的高级软件工程师,致力于暗黑破坏神4的开发。 谢谢你的合作,比尔!

图片[1]-暴雪暗黑破坏神4从visualstudio调试Linux内核转储-yiteyi-C++库

介绍

在Diablo IV上,我们在Windows上开发所有代码,并为多个平台编译。  这包括我们在Linux上运行的服务器。  (代码包括条件编译和自定义平台特定代码(必要时)。  此工作流有多种原因。  首先,我们团队的核心能力是Windows。  即使是我们的服务器程序员也非常熟悉Windows开发,我们非常欣赏团队中所有程序员使用通用工具集和知识库的能力。

我们在Windows上开发的另一个也是最重要的原因是visualstudio提供的功能和健壮的工具集。  在Linux世界中,没有什么可以与之相比,即使我们是在Linux中进行本机开发。

然而,当部署的服务器崩溃并且我们想要调试结果核心转储时,这给我们带来了一些挑战。  可以选择远程登录到崩溃的VM(或者更具体地说是容器),然后运行gdb来诊断那里的崩溃。  但这也有许多缺点。  首先,我们不使用二进制文件部署源代码,因此源代码在VM或容器上的gdb会话中不可用。

另一个障碍是gdb本身:除非您经常使用gdb,否则您无法保持对它的熟练程度以方便我们使用。  简单地说,我们的开发人员更愿意使用熟悉的工具进行调试。  由于我们的开发人员中只有2到3人精通gdb,因此他们实际上成为了诊断生产崩溃的资源,而这并不是最佳的。

我们一直希望有一种更直观的方法来调试Linux内核。  这就是为什么我们如此兴奋能够利用新的visualstudio功能,让我们在熟悉的visualstudio环境中做到这一点!  可以毫不夸张地说,这是梦想成真。

An image of combat gameplay in Diablo IV.

我们的调试工作流程

只有在安装WSL或 将Linux连接添加到连接管理器 . 我们所有的服务器开发人员都使用我们部署的发行版安装WSL。  我们运行我编写的脚本,该脚本还安装了在WSL中构建服务器所需的所有开发工具和支持库。

(作为一个简短的附带主题,我想强调的是,我们发现WSL是开发人员在Linux构建中测试其更改的最佳Linux环境。  跳转到WSL、cd到共享代码目录并从那里直接构建非常方便。  这是一个比运行VM甚至容器更好的解决方案。 如果您正在使用CMake进行构建,那么还可以利用visualstudio的 对WSL的本机支持 .)

让我提供一些关于我们构建的背景知识。  我们在Windows上开发代码,并且有一个Windows版本的服务器可以在Windows下运行。  这对于常规特征开发非常有用。  但是,我们将服务器部署在Linux上,这需要在Linux本身上生成一个构建。  Linux构建是在一个构建场上生成的,该构建场使用Linux盒上的构建系统来构建服务器及其部署的容器。  Linux可执行文件只部署在一个容器中,开发人员通常无权访问它。

当我们的基础设施中的服务器崩溃时,一个自动化的过程会通知我们,核心文件会归档到网络共享中。  要在Linux或visualstudio中调试内核,必须有正在运行的可执行文件;它还可以帮助调试已部署容器上使用的确切共享库。  我们使用另一个脚本来获取这些文件。  首先,我们将核心复制到本地机器上,然后运行脚本并将其指向核心。该脚本下载使用该版本构建的Docker容器,从中提取服务器二进制文件,以及某些供gdb使用的共享运行时库。  (这避免了在WSL版本与部署的Linux版本不完全匹配时可能遇到的gdb兼容性问题。)  脚本写入~/.gdbinit以将共享库设置为调试会话的系统库。

然后我们切换到visualstudio,在那里开始了乐趣。我们加载解决方案来构建服务器的Windows版本。然后在下面打开新的调试对话框 调试->其他调试目标->仅使用本机调试Linux核心转储 . 我们启用“在WSL上调试”复选框并填写(WSL特定的!)核心文件和服务器二进制文件的路径。在那之后,我们开始调试并观看节目!

图片[3]-暴雪暗黑破坏神4从visualstudio调试Linux内核转储-yiteyi-C++库

visualstudio在幕后调用WSL中的gdb。在一些磁盘活动之后,弹出一个针对崩溃的调用堆栈,指令指针位于相关的代码行上。这是一个勇敢的新世界!

所以接下来的任务就是确认坠机事件。我们有一个崩溃处理程序,它拦截崩溃以执行一些内务处理,因此实际的崩溃将在单线程服务器的调用堆栈中进行。然而,我们的一些服务器是多线程的,崩溃可能来自这些线程中的任何一个。我们的崩溃处理程序记录了崩溃文件的来源和行号,因此检查这些变量可以得到第一条线索;我们将查找执行该代码的调用堆栈。

在几周前的旧日子里,我们将使用gdb获取所有线程的回溯,并仔细查看结果列表,以查看哪个线程最有可能出现崩溃的调用堆栈。例如,如果一个线程正在休眠,那么它很可能不是崩溃的线程。我们将寻找一个堆栈,它的内容比用“sleep”覆盖的几个帧要多一些,并检查代码以查看问题是否明显,或者进入gdb本身来检查进程状态。

然而,visualstudio为我们提供了比这更强大的选项。对于多线程内核,您可以在调试会话中打开“线程”窗口,在每个线程中查看堆栈的外观。这与gdb方法非常相似,如果有50个线程,则会非常乏味。幸运的是,有一个功能使这更容易: 平行堆叠 .

我承认,在Erika Sweet和她的团队告诉我们之前,我们大多数人都不知道平行堆栈。调用Debug->Windows->Parallel Stacks(仅在调试会话期间可用)将打开一个新窗口,其中显示进程中每个线程的调用堆栈。这是一个迷人的30000英尺视图,您的整个过程空间。您可以双击任何线程中的任何堆栈帧,VisualStudio将在“源”和“调用堆栈”窗口中跳转到该帧。这对我们来说是一个巨大的时间节省。

一旦我们可以看到崩溃附近的代码,我们就可以使用鼠标悬停、QuickWatch或VisualStudio中的任何其他大量工具来检查变量。的确,在发布版本中,许多变量被优化了,但同时,许多变量没有优化!使用visualstudio的接口,我们可以比使用gdb更快地解决问题。

图片[4]-暴雪暗黑破坏神4从visualstudio调试Linux内核转储-yiteyi-C++库

摘要

我们的团队对于能够在visualstudio中从我们的生产环境中调试Linux内核感到非常兴奋!它改变了我们的游戏规则,因为它允许更多的开发人员“在野外”主动诊断问题,而且它使强大的visualstudio调试工具集对我们所有人都可用。一旦我们的初始设置完成,在visualstudio中调试会话只需要一分钟左右。这个特性将使在我们的代码中发现问题更快更有效!感谢埃里卡和她的团队与我们合作!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享