iOS编译原理-调试objc源码

537 阅读2分钟

一、背景

作为一名iOS开发,日常我们基本天天跟iOS对象打交道,但是创建、释放、引用底层是如何实现的呢?估计很多初级开发工程甚至一些高级开发工程师都是云里雾里,这篇文档主要是介绍如何编译objc底层源码,然后如何调试这些源码,大家后续就可以一步步根据断点分析iOS源码流程。

二、objc818.2源码调试,请准备如下内容:

三、编译objc,常见问题如下

解决:找不到 “'sys/reason.h' file not found”

第一步:在 opensource.apple.com/tarballs/xn… 下载 xnu-4903.241.1.tar.gzxnu/bsd/sys 找到 reason.h 然后把找到的文件按照如下操作加入到工程里面:

  1. 在项目根目录创建了一个 GGZCommon 文件夹
  2. 在 GGZCommon文件夹内创建 sys 文件夹
  3. 把 reason.h 文件加入进去

第二步:设置检索路径

  • 选择 target -> objc -> Build Settings
  • 在 Header Serach Paths 中加入路径 $(SRCROOT)/GGZCommon (Debug和Release都要设置)

解决: “'mach-o/dyld_priv.h' file not found“

Apple Source中找到“dyld-832.7.1 -> include -> mach-o -> dyld_priv.h”文件并下载,将mach-o/dyld_priv.h 加入 GGZCommon文件

解决: “dyld_priv.h:160:148: Expected ','”解决办法:将“bridgeos(3.0)”去掉。如下:

//将含有bridgeos(3.0)的代码注释
//extern dyld_platform_t dyld_get_base_platform(dyld_platform_t platform) __API_AVAILABLE(macos(10.14), iOS(12.0), watchos(5.0), tvos(12.0), bridgeos(3.0));
//修改后的代码
extern dyld_platform_t dyld_get_base_platform(dyld_platform_t platform) __API_AVAILABLE(macos(10.14), iOS(12.0), watchos(5.0), tvos(12.0));

解决: #include <pthread/tsd_private.h> 找不到

下载 libpthread-416.100.3将 pthread/tsd_private.h 拷贝到 GGZCommon/pthread 目录下

解决: #include<System/machine/cpu_capabilities.h>找不到

下载 libpthread-454.120.2 将 osfmk/machine/cpu_capabilities.h 拷贝到 GGZCommon/System/machine/ 目录下

解决: <pthread/spinlock_private.h> 找不到

下载 Libc-498 将 pthreads/spinlock_private 放入 GGZCommon/pthread 目录下

解决:include <CrashReporterClient.h>

还是一样 下载'CrashReporterClient.h文件, 这个在也在Libc中, 这里也是留意下Libc不能下最新的, 也是没有这个 CrashReporterClient.h文件, 在 Libc-825.26中

解决:#include <objc-shared-cache.h> 找不到

下载 dyld-832.7.1 2 将 pthreads/spinlock_private 放入 GGZCommon/pthread 目录下

解决:常见又熟悉的错误Use of undeclared identifier ‘CRGetCrashLogMessage’

  • 那么根据该宏定义的前一步、如果定义了 LIBC_NO_LIBCRASHREPORTERCLIENT 才会走下边的宏定义符号
  • 来到 Preprocessor Macros预编译处 定义这个变量 Xnip2022-10-30_13-36-00.jpg

解决: os/linker_set.h 头文件找不到

解决方案:直接注释掉 objc-class.mm 文件的 #include <os/linker_set.h> 这一行即可

解决:Block_private.h 找不到

下载 libclosure-78 将 Block_private.h 放入 GGZCommon/ 目录下

解决:Cambria/Traps.h 和 Cambria/Cambria.h 头文件找不到

解决方案:直接注释掉 objc-cache.mm 文件的 #include <Cambria/Traps.h> 和 #include <Cambria/Cambria.h> 这两行即可

解决: #include <kern/restartable.h> 头文件找不到

下载 xnu-7195.50.7.100.1 将 osfmk/kern/restartable.h 放入 GGZCommon/kern 目录下

解决: LINKER_SET_FOREACH 报错

解决方案:直接注释掉 objc-class.mm 的 896 - 902 行

解决:"objc-cache.mm:1122:33: Use of undeclared identifier 'objc_thread_get_rip'”

直接注释即可 Xnip2022-10-30_13-34-51.jpg

解决:os/reason_private.h 和 os/variant_private.h 头文件找不到

解决方案:直接注释掉 NSObject.mm 文件的 #include <os/reason_private.h> 和 #include<os/variant_private.h> 这两行即可。

解决:ld: can't open order file: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/AppleInternal/OrderFiles/libobjc.order clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决方法: Build Settings->Linking->Order File -> Debug 改成$(SRCROOT)/libobjc.order

解决: ld: library not found for -lCrashReporterClient clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决方法: 虽然我们添加了 CrashReporterClient 但还是在报错,所以直接删除引用。 在 TARGETS -> objc -> Build Settings -> Linking -> Other Linker Flags里删掉 Debug -> Any macOS SDKRelease -> Any macOS SDK 中的"-lCrashReporterClient" 删除之后如下 Xnip2022-10-30_13-37-15.jpg

解决:SDK "macosx.internal" cannot be located. Xnip2022-10-30_13-37-48.jpg

解决 : 'os/feature_private.h' file not found

解决方案 : 直接注释掉 #include <os/feature_private.h> 这一行, 涉及以下两处代码文件;

  1. NSObject.mm
  2. objc-runtime.mm

解决:

Unknown type name 'uint32_t'、 Use of undeclared identifier 'INT64_C'

解决方案:在失败的文件添加如下代码

#include <stdint.h>

解决

Assertion failed: (sel_registerName(sel_getName(meth.name())) == meth.name()), function methodizeClass, file objc-runtime-new.mm, line 1536.  
warning: could not find Objective-C class data in the process. This may reduce the quality of type information available.  
(lldb)

解决方案: 原因系统升级到13.0及之上导致,需要用最新的objc源码才可以

四、objc源码调试步骤

  1. 新建Target MyTest
  2. 添加依赖 Xnip2022-10-30_13-38-48.jpg
  3. 如果想断点调试 818.2 源码 需要做如下步骤 Xnip2022-10-30_13-39-20.jpg
  4. 选择 Target MyTest + 运行,会正常出现断点到runtime源码里啦 Xnip2022-10-30_13-40-18.jpg