lldb 入坑指北(2)-​ 15行代码搞定二进制与源码映射

时间:2022-07-28
本文章向大家介绍lldb 入坑指北(2)-​ 15行代码搞定二进制与源码映射,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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 命令背后的那些事儿

但是美中不足的是,文章中的解决方案存在以下问题:

  1. 强依赖 pod 相关组件,通用性较差
  2. 二进制组件编译路径需要保证相同
  3. 需要切换到 iTerm 等工具执行命令,破坏开发体验

03

为了解决以上问题,本文通过 lldb 提供的源码映射能力,实现了将任意的二进制文件映射到源码文件的通用方案。

ps.如果读者了解 lldb + python ,阅读以下代码会更加简单。

在 ~/.lldbinit (Xcode 启动时,会执行该脚本,所以新手请务必先关闭 Xcode 再进行操作)位置创建文件,并添加代码(文件路径可以根据自身情况调整)

command script import /Users/kukudeaidian/LLDB_MapFile.py

创建 /Users/kukudeaidian/LLDB_MapFile.py 文件,并添加下面的代码:

#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')