原文出自【听云技术博客】:http://blog.tingyun.com/web/a...html
序言linux
怎么在linux 平台下实现一个相似于mac 平台下的 atos 工具( iOS 符号化解析)?git
分析问题github
在github上找到了几年前的开源实现,https://github.com/dechaoqiu/atoslweb
编译出来的atosl工具日常很大概率是工做正常的,只有在特殊状况下会出现解析错误,主要表现为如下方式:小程序
一、使用Swift 编写的app ,编译出来的 atosl 必定会解析错误(乱码形式) swift
二、使用C+ + 实现的一些函数,编译出来的 atosl 解析出来的字符串也是乱码xcode
三、在解析 iOS 系统framwork 框架的时候 有概率会出现解析错误(乱码形式) app
四、用户的某些崩溃信息不能定位到具体的 line no,编译出来的 atosl服务只能解析出来offset。框架
iOS dSYM 文件结构剖析
在 iOS App 开发过程当中,咱们会利用Xcode打包,生成.xarchive的包文件,经过Xcode 的Organizer 工具能够管理并导出发布文件,iOS 开发者对这些过程都是轻车熟路,这里再也不重复阐述,主要想讲的是,打包以后生成的dSYM 文件。
dSYM 是一个目录,打开以后,咱们会找到一个二进制文件以下图
能够看出iOS 使用的是DWARF文件结构 (Debug With Attributed RecordFormats) 是一种调试文件结构标准,结构至关复杂。
https://www.prevanders.net/dwarf.html
dSYM 文件的一个重要做用就在于,当咱们的程序发生崩溃,经过crash log 或其余方式 ,会看到调用栈信息。 经过log信息,咱们并不知道具体是在哪个文件的哪个位置出了问题, 这个时候这个二进制文件提供的信息就很是有用了,经过它咱们能够经过工具 去符号化, Mac OS X 平台下 Xcode 自带了 atos 这样的工具,这样能够直接定位到某个文件的具体位置。 用法以下:
在 Mac OS 下有 dwarfdump 工具来解析DWARF文件,很显然解析出来的信息并不能知足咱们的全部需求。
dwarfdump -a SwfitTest
若是要了解其内部结构,请参考《iOS系统分析(二)Mach-O二进制文件解析》。
思路
github 下载 atosl 源代码,C写的
添加Cxx 与 Swift的错误样例
make test 结果以下,很明显 Cxx 与 Swift 符号化有问题,这就是我要解决的问题。
返回到mac os x中利用xcode 提供的 xcrun atos 处理,可以正确解析,(因此我要作的事情就是在linux平台下实现一个 相似于mac os x 平台下的 atos ->输入输出相同)
解决C+ + 乱码的思考过程,在前面学习分析 Mach-O 文件的时候 使用过一个 MachOView 工具,而后我用工具打开QuartzCore 这个dSYM 文件,发如今 SymTables 里面解析出来的 字符串也是乱码,可是神奇的事情发生了,当我鼠标停留在某一行乱码的时候 复出了正确的解析字符串,这说明 MachOView 是可以正确解析C + + 名字的。果断 github 搜源代码. 从这里知道了 编译器在编译过程当中会对函数作一些手脚,下面分析编译器的行为。
mangled symbol names (重整符号名称)
C/Cxx
在C这样的语言中,任何给定的名字(符号)只能对应惟一的一个函数或数据,不须要名字重整(name mangling)。即使如此,若是你看一个典型的纯C二进制的符号表,你会发现每一个函数名有一个 (下划线)的前缀,以下:
这种简单的“mangling”(重整)已有很长的历史,实际上没有多少用处,但仍为兼容性和一致性起到一些效果。按照惯例,C中定义的名字会有下划线,而纯汇编定义的全局符号则没有(尽管许多汇编语言的做者为了一致性,也会预先考虑下划线的定义)。
Objective-C
它的符号名字不会有异议或者说冲突;Objective-C的方法实现的形式是: -class selector,而且objective - c不容许相同的类使用不一样的参数来重载相同的selectors。
Cxx
一个没有额外信息的简单的名字可能会产生异议,因此必须作一些处理, 以下:
由于function对应两个包含不一样参数的函数,这在cxx中是合法的定义,因此咱们不能简单地生成两个_ function符号,由于连接器会不知道如何连接,没法区分不一样的函数实现。所以,cxx编译器使用一组严格的编码规则“mangles”(重整)了符号。
Swift
最开始的字符’-‘对Swift符号是必须的
‘-T’是Swift全局符号的标记
解决方法
按照这个规则本身去还原符号也是可行的,不过仍是比较费时,还可能有bug。
幸亏Xcode 自带了个工具, 能够查看这些 mangled name 的原本面目,就不须要本身从新去实现.
解决思路过程
既然apple 提供了工具,那么我就不须要去本身写了,直接调用便可,在xcode的目录中找到了工具地址以下:
第一种解决方法 :管道通讯 atosl 直接调用 swift-demangle 。
第二种解决方法 : 将swift-demangle.dylib 连接到程序中。
正确解析。接下来要想办法将这个小程序移植到Linux 平台下。
我猜这是Swift提供的工具,Google 发现Swift是源代码级别开源,果真支持Linux。
在linux上编译 Swift
配置环境编译之(Ubuntu 14.04),编译过程当中有坑(内存必须配置5GB以上,硬盘30GB 以上)
warning:若是你遇到相似 clang: error: unable to execute command: Killed 的报错,不要多想,就是内存爆了,多试几回也许就成功了。
若是一切正常1小时就能编译完毕(个人硬件环境 MacBookAir 1.4GHz CPU 8GB 内存 固态硬盘,用了将近1个小时)。
第一种解决方案:swift编译完成后 在build/xxx/xxx/xxx/bin 下果真有ELF这个可执行文件
第二种解决方案: 使用编译出来的库文件
在lib目录下 没有找到 .so动态库,纳闷好久(swift的 编译脚本使用的是Cmake) Darwin 这个术语是指 mac 系统内核核心 (包括 xnu kernel 与 Unix Shell 环境),注释掉这里就能够将(Linux 共享库) .so 编译出来,若是要编译静态库 则须要修改cmake脚本,以下图:
共享库编译出来了,则直接动态连接到 atosl中,swift 只能在Ubutun上编译,若是最终你的atosl 要在 Linux的其余发行版上运行,最好将全部的依赖库用静态连接。
2
make test
测试发现 cxx 与Swift的测试样例 的 offset(定位到的 line no 解析不出来),github上的代码已经好久没有人维护了,最后仍是果断重写之。
end
(有任何问题请联系 email:liutianshxkernel@gmail .com)