如何从macOS应用中手动符号化崩溃日志(附代码)

594 阅读5分钟

你的一个Mac应用程序崩溃了吗?如果你从用户那里得到了一份崩溃报告,或者从Sentry那里得到了一份没有符号的崩溃日志,我将指导你如何将其解码为你可以用来调试崩溃的东西。

对于我自己的应用程序Recut,我已经添加了Sentry库来捕获崩溃报告。不管是什么原因,Sentry并没有将我的崩溃报告符号化。我已经上传了dSYMs,但它似乎对它们视而不见。所以。我就自己把它们符号化吧!

下面是如何手动操作的,我还编写了一个Ruby脚本来符号化整个崩溃报告

1.从Sentry下载未符号化的崩溃报告。

在错误报告中,选择RawUnsymbolicated ,然后点击下载。在你选择Raw之前,下载按钮不会出现。不要把它作为默认的Symbolicated ,否则下载的日志会有一堆<redacted> ,而这些地方应该是内存地址。

Symbolication options in Sentry

2.制作一个新的空文件夹

然后打开一个终端,cd 到你的新文件夹。我们将在这里复制必要的文件,因为它们都需要在一个地方才能正确地符号化。

3.打开Xcode和组织者

在Xcode中,在Window菜单下,点击Organizer来打开它。

这里面包含了你的应用程序的所有存档的构建。

4.找到正确的版本

将崩溃日志中的信息(或Sentry中的信息)与Xcode的组织者中的版本列表相匹配,并选择一个匹配的版本。

除非所有的版本都吻合,否则符号化将无法正常工作(或者根本无法工作?

在我的例子中,我使用的是2.0.1版本,构建552。

Xcode Organizer window showing available releases

5.把文件从版本中复制出来

右键单击发行版,并选择在Finder中显示。

这将打开一个Finder窗口,里面有一个单一的.xcarchive 文件。

右键单击该xcarchive,并选择显示软件包内容。

你应该看到一堆这样的文件夹。

An example of a .xcarchive folder

我们需要的文件在两个地方。

  • dSYMs :把所有东西都复制到你创建的文件夹中。
  • fromProducts/Applications: 将你的应用程序复制到同一文件夹中。

请确保你复制了这些文件!不要移动它们。

这个xcarchive是你进入王国的钥匙......如果你失去了这些文件,你将无法再象征性地编写崩溃报告。所以不要管原始文件,只管复制。

6.运行symbolicator工具

你应该有一个预装的命令行工具,叫做atos 。从它的man 页面,它的工作是 "将数字地址转换为二进制图像或进程的符号"。

现在在你的文件夹中,你应该至少有这3样东西:

  • 崩溃报告文件(一个文本文件)
  • YourApp.app.dSYM
  • YourApp.app

你可以通过将几个内存地址插入atos 来手动符号化一个单行。例如,这里是我的应用程序中崩溃的前几行:

Thread 0 Crashed:
0   Recut                           0x204302872         0x204296000 + 444530
1   Recut                           0x204308b5c         0x204296000 + 469852
2   Recut                           0x204308afe         0x204296000 + 469758

为了查找发生崩溃的函数和文件,我将使用前两个内存地址并运行atos

atos -o Recut.app/Contents/MacOS/Recut -arch x86_64 -l 0x204296000 0x204302872

这样就可以打印出崩溃的位置,我就可以去找它了:

closure #1 in WaveDataManager.samplesForResolution(_:) (in Recut) (WaveDataManager.swift:150)

7.运行一个脚本来自动符号化一切

我写了一个Ruby脚本,在每个相关的行上运行atos 命令,并一次性地将整个崩溃报告符号化。它就在GitHub的gist中

要使用它:

  1. 下载它
  2. 使其可执行chmod +x ./symbolicate.rb
  3. 在你的文件上运行它。
symbolicate.rb 53c91214f29a42f1a0d19f86b7236e70.crash x86_64 Recut.app Recut.app.dSYM

这将打印出崩溃报告,但其中有你自己应用程序的调用符号:

Thread 0 Crashed:
0   Recut                           0x204302872         closure #1 in WaveDataManager.samplesForResolution(_:) (in Recut) (WaveDataManager.swift:150)
1   Recut                           0x204308b5c         thunk for @callee_guaranteed () -> () (in Recut) (<compiler-generated>:0)
2   Recut                           0x204308afe         thunk for @escaping @callee_guaranteed () -> () (in Recut) (<compiler-generated>:0)
...

你可以通过-g ,对输出进行着色,以突出与你的应用程序的代码相对应的行。

默认情况下,它隐藏了不包含任何对你的应用程序代码的调用的线程。它还隐藏了崩溃报告结尾处的二进制文件的大列表。你可以用标志来关闭这些。

这里有完整的使用信息:

Usage: symbolicate -g -b -t [crash_log] [arch] [app_bundle] [dsym]

The crash log, app, and dSYM should all be in the current working directory.

  In Xcode: Window > Organizer
  right-click the release, Show in Finder
  right-click the xcarchive, Show Package Contents
  copy files from `dSYMs` and `Products/Applications` into a new empty folder
  copy the crash log to the same folder

-g          Colorize the output to highlight this app's lines
-b          Show the 'Binary Images' section (by default this is omitted for brevity)
-t          Show all threads, including ones that have no calls to your app
crash_log   text file from Sentry
arch        x86_64 or arm64 (get this from Sentry)
app_bundle  TheApp.app (in current directory)
dsym        TheApp.app.dSYM (in current directory)

现在去调试吧!

我希望这能帮助你完成你自己的应用程序的调试之旅!