摘要
本文主要记录了 iOS 移动端的一个疑难 bug 的排查过程,以及介绍通过给 bitcode 打补丁重新生成机器码,为有问题的第三方库修复 bug 的方法。
主要涉及到的知识点如下:
-
ARM 汇编
-
C++ 运行时
-
静态库文件的结构
-
bitcode 及 LLVM IR
平台监控找崩溃
通过内部的崩溃监控发现,有一个内部 App,近期出现了较多的崩溃现象。其中数量占比最多的崩溃,其崩溃线程捕获到的调用栈如下:
libsystem_kernel.dylib 0x00000001cc78c414 ___pthread_kill + 7
libsystem_c.dylib 0x00000001a7db2b74 _abort + 103
App 0x0000000103092868 ___48-[BLYLogicManager abortAfterSendingReportIfNeed]_block_invoke + 87
libdispatch.dylib 0x000000019e60824c __dispatch_call_block_and_release + 31
libdispatch.dylib 0x000000019e609db0 __dispatch_client_callout + 19
libdispatch.dylib 0x000000019e61aa68 __dispatch_root_queue_drain + 655
libdispatch.dylib 0x000000019e61b120 __dispatch_worker_thread2 + 115
libsystem_pthread.dylib 0x00000001ea1e77c8 __pthread_wqthread + 215
调用现场出端倪
这个调用栈并没有提供什么有效的信息,只能看出来是 bugly 框架已经检测到了崩溃创建了新的 dispatch queue 并终止进程,也就是说,其实有效的崩溃信息被 bugly 给吃掉了。
看一下其他线程,是否有可用的信息,一般可以在其他线程的调用栈上搜索以下内容:
-
_ZSt9terminateEv
: C++ 的终端异常处理(std::terminate(void)
) -
__sigtramp
: 信号中断处理例程入口
终于搜索到了以下内容:
Thread #52: id=1a6c6, name=
libsystem_kernel.dylib 0x00000001cc78cf5c ___ulock_wait + 7
libdispatch.dylib 0x000000019e60a528 __dispatch_thread_event_wait_slow + 55
libdispatch.dylib 0x000000019e618708 ___DISPATCH_WAIT_FOR_QUEUE__ + 351
libdispatch.dylib 0x000000019e6182b0 __dispatch_sync_f_slow + 147
App 0x00000001030925f0 -[BLYLogicManager executeEmergencyLogic:] + 695
App 0x000000010308b6a8 -[BLYCrashManager sendLiveCrashReport] + 203
App 0x000000010305f478 _BLYCrashHandlerCallback + 5555
App 0x000000010305bc2c _BLYBSDSignalHandlerCallback + 95
libsystem_platform.dylib 0x00000001ea1e1290 __sigtramp + 55
App 0x00000001029543dc *redacted*
App 0x00000001029543dc *redacted*
App 0x00000001028a1918 *redacted*
App 0x00000001027ea9c4 *redacted*
App 0x00000001027ea794 *redacted*
App 0x00000001027ead60 *redacted*
libsystem_pthread.dylib 0x00000001ea1e5b40 __pthread_start + 319
内部应用同时集成了 Bugly 和自有的崩溃捕获,通常情况下 Bugly 会在自己捕获完成后,将崩溃现场转交给其他框架,使两次捕获的崩溃现场相同。而这个崩溃则不然, Bugly 捕获了崩溃后,直接调用 abort
结束了应用,导致自有崩溃只捕获到了 SIGABRT
。
通过检查主线程调用栈,发现了一些不同:
Thread #0: id=1a0d3, name=
libsystem_kernel.dylib 0x00000001cc78c1ac ___psynch_cvwait + 7
libc++.1.dylib 0x00000001b3a25328 __ZNSt3__118condition_variable4waitERNS_11unique_lockINS_5mutexEEE + 27
App 0x000000010280e5c8 *redacted*
App 0x00000001027e9414 *redacted*
App 0x00000001027e9380 *redacted*
libsystem_c.dylib 0x00000001a7d930b8 ___cxa_finalize_ranges + 423
libsystem_c.dylib 0x00000001a7d93400 _exit + 27
UIKitCore 0x00000001a13d4bdc -[UIApplication _terminateWithStatus:] + 503
UIKitCore 0x00000001a0a23648 -[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:] + 127
UIKitCore 0x00000001a0a23278 -[_UISceneLifecycleMultiplexer forceExitWithTransitionContext:scene:] + 219
UIKitCore 0x00000001a13ca644 -[UIApplication workspaceShouldExit:withTransitionContext:] + 211
FrontBoardServices 0x00000001ae6d2780 -[FBSUIApplicationWorkspaceShim workspaceShouldExit:withTransitionContext:] + 87
FrontBoardServices 0x00000001ae701390 ___63-[FBSWorkspaceScenesClient willTerminateWithTransitionContext:]_block_invoke_2 + 79
FrontBoardServices 0x00000001ae6e54a0 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 239
FrontBoardServices 0x00000001ae701328 ___63-[FBSWorkspaceScenesClient willTerminateWithTransitionContext:]_block_invoke + 131
libdispatch.dylib 0x000000019e609db0 __dispatch_client_callout + 19
libdispatch.dylib 0x000000019e60d738 __dispatch_block_invoke_direct + 267
FrontBoardServices 0x00000001ae72a250 ___FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 47
FrontBoardServices 0x00000001ae729ee0 -[FBSSerialQueue _t