美文网首页
[译]《iOS Crash Dump Analysis》-

[译]《iOS Crash Dump Analysis》-

作者: iOS成长指北 | 来源:发表于2021-01-26 14:34 被阅读0次

macOS 崩溃报告导览

尽管 macOS CrashReport 和 iOS CrashReport 是截然不同的程序,但 macOS 崩溃报告类似于 iOS 崩溃报告。为了避免重复,这里我们只强调与 iOS 的显着差异。

macOS 崩溃报告 Header 部分

崩溃报告以一下部分开头:

Process:               SiriNCService [1045]
Path:                  /System/Library/CoreServices/Siri.app/
Contents/XPCServices/SiriNCService.xpc/
Contents/MacOS/SiriNCService
Identifier:            com.apple.SiriNCService
Version:               146.4.5.1 (146.4.5.1)
Build Info:            AssistantUIX-146004005001000~1
Code Type:             X86-64 (Native)
Parent Process:        ??? [1]
Responsible:           Siri [863]
User ID:               501

这里我们看到了熟悉的描述故障二进制信息。崩溃的进程是 SiriNCService,负责这个进程的是 Siri。在 Siri 和 SiriNCService 之间的跨进程通信时发生了崩溃(XPC)。

通常 iOS以一个用户身份运行用户体验的系统,然而 macOS系统却暴露出系统中存在多个用户 ID 的事实。

macOS 崩溃报告 Date 和 Version 部分

接下来我们来看版本信息:

Date/Time:             2018-06-24 09:52:01.419 +0100
OS Version:            Mac OS X 10.13.5 (17F77)
Report Version:        12
Anonymous UUID:        00CC683B-425F-ABF0-515A-3ED73BACDDB5

Sleep/Wake UUID:       10AE8838-17A9-4405-B03D-B680DDC84436


Anonymous UUID 将是计算机的唯一标识。 Sleep/Wake UUID 用于匹配睡眠和唤醒事件。唤醒失败是系统崩溃的常见原因(与我们讨论的应用程序崩溃相反)。可以使用电源管理命令 pmset 获取更多信息。

macOS 持续时间部分

macOS 崩溃报告显示应用程序崩溃发生的时间。

Time Awake Since Boot: 100000 seconds
Time Since Wake:       2000 seconds

我们使用它作为一个广泛的指示只因为看到的数字总是四舍五入所得到一个方便的数字。

macOS崩溃报告系统完整性部分

System Integrity Protection: enabled

默认情况下,现代 macOS 运行是 "rootless"的。这意味着即使我们以超级用户身份登录,我们也无法更改系统的二进制文件。这些都是通过固件进行保护的。可以在禁用系统完整性保护的情况下启动 macOS。如果我们只是在禁用 SIP 的情况下崩溃,那么我们需要问为什么 SIP 会关闭以及对操作系统做了哪些更改。

macOS 崩溃报告的异常部分

接下来展示异常部分。

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000018
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [0]

VM Regions Near 0x18:
-->
    __TEXT                 0000000100238000-0000000100247000
     [   60K] r-x/rwx SM=COW  
     /System/Library/CoreServices/Siri.app/
     Contents/XPCServices/SiriNCService.xpc/Contents/MacOS/
     SiriNCService

Application Specific Information:
objc_msgSend() selector name: didUnlockScreen:

这与 iOS 类似。但是,我们应该注意,如果我们在模拟器上重现 iOS 崩溃,那么模拟器可能会以不同方式对相同的编程错误进行建模。我们可以在 x86 硬件上获得与 ARM 对应的异常。

考虑以下代码,设置为旧版的手动引用计数(MRC)而不是自动引用计数(ARC)。

void use_sema() {
    dispatch_semaphore_t aSemaphore =
     dispatch_semaphore_create(1);
    dispatch_semaphore_wait(aSemaphore, DISPATCH_TIME_FOREVER);
    dispatch_release(aSemaphore);
}

代码会导致崩溃,因为在等待时会手动释放信号量。

当它在 ARM 硬件上的 iOS 模拟器上运行时,会发生崩溃

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000001814076b8
Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [0]
Triggered by Thread:  0

Application Specific Information:
BUG IN CLIENT OF LIBDISPATCH: Semaphore object deallocated while
 in use
 Abort Cause 1

当它在 iOS 模拟器上运行时,我们会附带调试器

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

模拟器使用错误的汇编指令来触发崩溃。

此外,如果我们编写一个运行相同代码的 macOS 应用程序,我们就会崩溃:

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes:       0x0000000000000001, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Illegal instruction: 4
Termination Reason:    Namespace SIGNAL, Code 0x4
Terminating Process:   exc handler [0]

Application Specific Information:
BUG IN CLIENT OF LIBDISPATCH:
Semaphore object deallocated while in use

这就带来一个信息,当通过模拟器或等效的 macOS 代码在 x8 6硬件上再现 iOS ARM 崩溃时,由于运行时环境有所不同,表现也会稍有不同。

幸运的是,在两个崩溃报告中都很明显的表明了信号量被释放了。

macOS 崩溃报告线程部分

接下来是线程部分。这部分类似于iOS。

接下来用示例说明 macOS 崩溃报告中的线程部分:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libobjc.A.dylib                 
0x00007fff69feae9d objc_msgSend + 29
1   com.apple.CoreFoundation        0x00007fff42e19f2c
 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
2   com.apple.CoreFoundation        0x00007fff42e19eaf
___CFXRegistrationPost_block_invoke + 63
3   com.apple.CoreFoundation        0x00007fff42e228cc
 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
4   com.apple.CoreFoundation        0x00007fff42e052a3
__CFRunLoopDoBlocks + 275
5   com.apple.CoreFoundation        0x00007fff42e0492e
__CFRunLoopRun + 1278
6   com.apple.CoreFoundation        0x00007fff42e041a3
CFRunLoopRunSpecific + 483
7   com.apple.HIToolbox             0x00007fff420ead96
RunCurrentEventLoopInMode + 286
8   com.apple.HIToolbox             0x00007fff420eab06
ReceiveNextEventCommon + 613
9   com.apple.HIToolbox             0x00007fff420ea884
 _BlockUntilNextEventMatchingListInModeWithFilter + 64
10  com.apple.AppKit                0x00007fff4039ca73
_DPSNextEvent + 2085
11  com.apple.AppKit                0x00007fff40b32e34
-[NSApplication(NSEvent) _nextEventMatchingEventMask:
untilDate:inMode:dequeue:] + 3044
12  com.apple.ViewBridge            0x00007fff67859df0
-[NSViewServiceApplication nextEventMatchingMask:
untilDate:inMode:dequeue:] + 92
13  com.apple.AppKit                0x00007fff40391885
-[NSApplication run] + 764
14  com.apple.AppKit                0x00007fff40360a72
NSApplicationMain + 804
15  libxpc.dylib                    0x00007fff6af6cdc7
 _xpc_objc_main + 580
16  libxpc.dylib                    0x00007fff6af6ba1a
 xpc_main + 433
17  com.apple.ViewBridge            0x00007fff67859c15
-[NSXPCSharedListener resume] + 16
18  com.apple.ViewBridge            0x00007fff67857abe
 NSViewServiceApplicationMain + 2903
19  com.apple.SiriNCService         0x00000001002396e0
 main + 180
20  libdyld.dylib                   0x00007fff6ac12015
 start + 1

macOS 崩溃报告线程状态部分

macOS 崩溃报告显示了崩溃线程中 X86 寄存器的详细信息。

Thread 0 crashed with X86 Thread State (64-bit):
  rax: 0x0000600000249bd0  rbx: 0x0000600000869ac0
    rcx: 0x00007fe798f55320
    rdx: 0x0000600000249bd0
  rdi: 0x00007fe798f55320  rsi: 0x00007fff642de919
    rbp: 0x00007ffeef9c6220
    rsp: 0x00007ffeef9c6218
   r8: 0x0000000000000000   r9: 0x21eb0d26c23ae422
     r10: 0x0000000000000000
     r11: 0x00007fff642de919
  r12: 0x00006080001e8700  r13: 0x0000600000869ac0
    r14: 0x0000600000448910
    r15: 0x0000600000222e60
  rip: 0x00007fff69feae9d  rfl: 0x0000000000010246
    cr2: 0x0000000000000018

Logical CPU:     2
Error Code:      0x00000004
Trap Number:     14

除与了 iOS 相似的信息之外,我们还获得了更多有关运行该线程的 CPU 的消息 。如果有需要我们可以在 Darwin XNU 源代码中查找对应的 trap number

Darwin XNU 源代码的便捷镜像由 GitHub 来托管:https://github.com/apple/darwin-xnu

这些 trap number 可以被搜索到。我们从osfmk/x86_64/idt_table.h 可以找到 Trap Number:14 表明看了一个页面错误。这个错误代码是一个位向量,用于描述在 mach 上的错误代码。@macherror

macOS 崩溃报告 Binary Images 部分

接下来,是崩溃应用程序所加载的 Binary Images。

以下是崩溃报告中前几个二进制文件的示例,为了便于演示,进行了截断:

Binary Images:
       0x100238000 -        0x1ß00246fff
         com.apple.SiriNCService (146.4.5.1 - 146.4.5.1)
          <5730AE18-4DF0-3D47-B4F7-EAA84456A9F7>
           /System/Library/CoreServices/Siri.app/Contents/
           XPCServices/SiriNCService.xpc/Contents/MacOS/
           SiriNCService

       0x101106000 -        0x10110affb
         com.apple.audio.AppleHDAHALPlugIn (281.52 - 281.52)
          <23C7DDE6-A44B-3BE4-B47C-EB3045B267D9>
           /System/Library/Extensions/AppleHDA.kext/Contents/
           PlugIns/AppleHDAHALPlugIn.bundle/Contents/MacOS/
           AppleHDAHALPlugIn

当二进制旁边出现 + 号时,则意味着它是操作系统的一部分。但是,我们看到某些第三方二进制旁边出现 + 号而系统二进制文件旁没有出现 + 号的示例,因为 + 并不是可靠的指示符(在 OS X 10.13.6上进行了最后测试)。

macOS 崩溃报告修改摘要

接下来,这一节描述了崩溃过程中的所有外部修改:

External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 184
    thread_create: 0
    thread_set_state: 0
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 72970
    thread_create: 0
    thread_set_state: 0

macOS 是比 iOS 更开放的平台。这就允许在某些条件下运行过程中发生了修改。我们需要知道是否发生了这种事情,因为它可以使代码中的任何设计假设无效,由于可以在过程中修改寄存器,这就有可能导致项目崩溃。

通常我们可以看到如上的快照。值得注意的是,在所有情况下,thread_set_state 值均为 0。这意味着并没有任何进程直接连接到该进程来更改寄存器状态。这种操作对于托管运行时或调试器的实现是可接受的。在这些情况之外的操作会显得奇怪,需要进一步调查。

在下面的示例中,我们看到线程状态除了200个 task_for_pid 调用之外,还一次被外部进程更改了。

External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 201
    thread_create: 0
    thread_set_state: 1
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 6184
    thread_create: 0
    thread_set_state: 1

这些数据通常会让我们对应用程序在崩溃之前运行的环境产生怀疑。

通常只有第一等的程序(Apple 提供的)才有权限执行上述修改。我们可以安装执行这个操作的软件。

执行访问进程修改的 API 有如下要求:

  • 需要禁用系统完整性保护

  • 进行修改的过程必须以 root 身份运行

  • 进行修改的程序必须经过代码签名

  • 程序必须被分配这些权利,将 SecTaskAccess 设置为 alloweddebug

  • 用户必须同意在其安全设置中信任该程序

示例代码 tfpexample 演示了这一点。 @icdabgithub

macOS 崩溃报告虚拟内存部分

崩溃报告接下来是虚拟内存摘要和区域类型细分。如果我们有一个用来渲染文档页面的图形丰富的应用程序,则可以查看,例如 CoreUI 的内存消耗。尽当我们用 Xcode Instruments 中的 memory profiler 工具分析该应用程序时,虚拟内存统计信息才有意义,因为这样我们就可以了解应用程序中内存的动态使用情况,从来在错误发生时发现错误。

这是报告的虚拟内存部分的示例:

VM Region Summary:
ReadOnly portion of Libraries: Total=544.2M resident=0K(0%)
swapped_out_or_unallocated=544.2M(100%)
Writable regions: Total=157.9M written=0K(0%) resident=0K(0%)
swapped_out=0K(0%) unallocated=157.9M(100%)

                                VIRTUAL   REGION
REGION TYPE                        SIZE    COUNT (non-coalesced)
===========                     =======  =======
Accelerate framework               128K        2
Activity Tracing                   256K        2
CoreAnimation                      700K       16
CoreGraphics                         8K        2
CoreImage                           20K        4
CoreServices                      11.9M        3
CoreUI image data                  764K        6
CoreUI image file                  364K        8
Foundation                          24K        3
IOKit                             7940K        2
Image IO                           144K        2
Kernel Alloc Once                    8K        2
MALLOC                           133.1M       36
MALLOC guard page                   48K       13
Memory Tag 242                      12K        2
Memory Tag 251                      16K        2
OpenGL GLSL                        256K        4
SQLite page cache                   64K        2
STACK GUARD                       56.0M        6
Stack                             10.0M        8
VM_ALLOCATE                        640K        8
__DATA                            58.3M      514
__FONT_DATA                          4K        2
__GLSLBUILTINS                    2588K        2
__LINKEDIT                       194.0M       26
__TEXT                           350.2M      516
__UNICODE                          560K        2
mapped file                       78.2M       29
shared memory                     2824K       11
===========                     =======  =======
TOTAL                            908.7M     1206

macOS崩溃报告系统配置文件部分

崩溃报告的下一部分是相关硬件的摘要:

System Profile:
Network Service: Wi-Fi, AirPort, en1
Thunderbolt Bus: iMac, Apple Inc., 26.1
Boot Volume File System Type: apfs
Memory Module: BANK 0/DIMM0, 8 GB, DDR3, 1600 MHz, 0x802C,
 0x31364B544631473634485A2D314736453220
Memory Module: BANK 1/DIMM0, 8 GB, DDR3, 1600 MHz, 0x802C,
 0x31364B544631473634485A2D314736453220
USB Device: USB 3.0 Bus
USB Device: BRCM20702 Hub
USB Device: Bluetooth USB Host Controller
USB Device: FaceTime HD Camera (Built-in)
USB Device: iPod
USB Device: USB Keyboard
Serial ATA Device: APPLE SSD SM0512F, 500.28 GB
Model: iMac15,1, BootROM IM151.0217.B00, 4 processors,
 Intel Core i5, 3.5 GHz, 16 GB, SMC 2.22f16
Graphics: AMD Radeon R9 M290X, AMD Radeon R9 M290X, PCIe
AirPort: spairport_wireless_card_type_airport_extreme
 (0x14E4, 0x142), Broadcom BCM43xx 1.0 (7.77.37.31.1a9)
Bluetooth: Version 6.0.6f2, 3 services, 27 devices,
 1 incoming serial ports

有时,我们的应用程序与硬件设备进行紧密交互,如果通过基于标准的设备接口(例如 USB 接口)进行交互,则有可能会发生很多变化。考虑一下磁盘驱动。许多供应商提供磁盘驱动器,它们可能直接或独立运行。它们可以直接连接,或通过 USB 电缆连接,也可以通过 USB 集线器连接。

有时新的硬件,例如新型 MacBook Pro 会出现自己的硬件问题,因此可以看到与我们的应用程序无关的崩溃。

判断是否是硬件环境导致崩溃的关键是查看大量的崩溃报告以寻找某种规律。

作为应用程序开发人员,我们只会看到应用程序中的崩溃。但如果我们与提供崩溃的用户联系,我们可以询问是否有其他应用程序崩溃,或者是否存在任何系统稳定性问题。

另一个有趣的方面是,并非所有硬件都始终被系统主动使用。例如,当 MacBook Pro 连接到外部显示器时,将使用不同的图形RAM,并使用不同的图形卡(外部GPU与内部GPU)。如果我们的应用程序执行特殊操作,则在连接到外部显示器时,故障可能出在硬件而非我们的代码中,原因是它触发了硬件中的潜在故障。

运行系统诊断程序并查看仅针对特定的匿名 UUID 故障报告是否出现问题,是尝试并了解应用程序是否存在特定的计算机硬件问题的方法。

相关文章

网友评论

      本文标题:[译]《iOS Crash Dump Analysis》-

      本文链接:https://www.haomeiwen.com/subject/vypgzktx.html