http://mpvideo.qpic.cn/tjg_3013949891_50000_5817e3ee3a3244308677fd52dcfc2a8f.f10002.mp4?dis_k=8605d88bdf927d7a3a08f7b96e79674b&dis_t=1603678587&vid=wxv_946692237352665090&format_id=10002
01
—
随着项目的扩大,为了提高开发效率、编译速度,组件化(二进制化)是一种不可避免的趋势。
大部分的公司都分享过相关文章,本文不再赘述。下面集中在二进制化带来的问题,以及相应的解决方案。
02
—
二进制在带来便利的同时,也带来一些新问题:
1、局部变量信息缺失
2、断点调试成本增加
3、汇编代码晦涩难懂
很多大厂都对此进行了研究,美团技术最近也做过一篇分享:
美团 iOS 工程 zsource 命令背后的那些事儿
但是美中不足的是,文章中的解决方案存在以下问题:
- 强依赖 pod 相关组件,通用性较差
- 二进制组件编译路径需要保证相同
- 需要切换到 iTerm 等工具执行命令,破坏开发体验
03
—
为了解决以上问题,本文通过 lldb 提供的源码映射能力,实现了将任意的二进制文件映射到源码文件的通用方案。
ps.如果读者了解 lldb python ,阅读以下代码会更加简单。
在 ~/.lldbinit (Xcode 启动时,会执行该脚本,所以新手请务必先关闭 Xcode 再进行操作)位置创建文件,并添加代码(文件路径可以根据自身情况调整)
代码语言:javascript复制command script import /Users/kukudeaidian/LLDB_MapFile.py
创建 /Users/kukudeaidian/LLDB_MapFile.py 文件,并添加下面的代码:
代码语言:javascript复制#encoding=utf-8
import lldb
import re
import os
# command 是用户输入的符号地址
def sun_map_address(debugger, command, result, internal_dict):
print(command)
# 获取 lldb 的命令交互环境,可以动态执行一些命令,比如 po obj
interpreter = lldb.debugger.GetCommandInterpreter()
# 创建一个对象,命令执行结果会通过该对象保存
returnObject = lldb.SBCommandReturnObject()
# 通过 image loopup 命令查找输入符号地址所在的编译模块信息
interpreter.HandleCommand('image lookup -v --address ' command, returnObject)
# 获取返回结果
output = returnObject.GetOutput();
# 下面的代码设计思想是:
# 1、根据{地址}查找该地址所属的{源码编译路径} {编译文件名}
# 2、通过{编译文件名}动态在{指定路径}查找相应的{源码路径}
# 3、将{源码编译路径}与{源码路径}映射
# 实际使用时,可以参考下面的方案。
# 1、根据{地址}查找该地址所属的{编译模块}。比如,SDWebImage
# 2、通过脚本动态下载{编译模块}的{源码仓库}
# 3、将{编译模块}与{源码仓库}映射
# 通过正则获取二进制编译时,源码的真正路径
filePath = re.match(r'(.|n)*file = "(.*?)".*', output,re.M).group(2)
# 通过真正路径获取编译源文件的文件名
fileName = re.match(r'/.*/(.*)', filePath).group(1)
# 通过文件名在 ~/MMAViewabilitySDK_iOS 目录(可以是任意的地址或者通过 git clone 动态下载)下查找源文件
sourcePath = os.popen('mdfind -onlyin ~/MMAViewabilitySDK_iOS ' fileName).read().replace('n','')
# 通过 lldb 提供的 settings set target.source-map 命令执行编译源码位置与当前源码位置的映射
interpreter.HandleCommand('settings set target.source-map ' filePath ' ' sourcePath, returnObject)
# 添加一个 扩展命令。sun_map_address
# 在 lldb 输入 sun_map_address 0x10803839 时,会执行 lldb_MapFile.py 文件的 sun_map_address 方法
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand('command script add sun_map_address -f lldb_MapFile.sun_map_address')