平时工作中会经常用到命令行工具Command Lines Tool。而Command Line Tool本质是一个命令行工具包,内部有很多有用的工具,如Apple LLVM compiler、Make等。而它里面中的一部分工具属于 LLVM 序列,比如dwarfdump、ar其本质为llvm-dwarfdump、llvm-ar。
Command Lines Tool中命令工具的执行需要2个前置工具xcode-select和xcrun。
工具简介
1.前置工具xcode-select和xcrun
2.构建工具
xcodebuild 构建
xctool 构建
altool 上传
3.符号相关
dwarfdump 查看
dsymutil 取提
symbolicatecrash 符号化
atos 符号化
4.MachO工具
nm 查看符号表
otool 查看包内容
objdump 查看包内容
lipo 拆包和合并
strings 查看字符串
ar 创建、修改静态库
file 查看文件
5.工具链相关
swiftc 编译前端
clang 编译前端
6.工具相关
actool Assets 压缩
swift-demangle 显示正确类名
前置工具xcode-select和xcrun
xcode-select
前置工具xcode-select用于选择执行哪个工具包中的命令工具。
我们在电脑上有时候会保存了多个Command Lines Tool命令行工具包,如安装了多个XCode或用户自己在本地也下载了Command Lines Tool工具包。那使用的时候是用哪个呢?
这时需要用xcode-select来指定。
如果使用命令单独安装Command Lines Tool工具包时,默认默认安装到系统目录下
xcode-select --install: 安装 CLI,会安装到/Library/Developer/CommandLineTools/
当下载Xcode时,Xcode的内部也内置了这个工具包。
xcode-select -p: 显示当前指定的工具包所在 Xcode 路径 xcode-select -s <path>: 切换默认工具包所在 Xcode 路径
xcrun
使用前置工具xcode-select选择的Command Lines Tool工具包来执行命令行工具。
xcodebuild archive -workspace ${WORKSPACE_PATH} -scheme ${SCHEME_NAME} -archivePath ${ARCHIVE_PATH}
如上面这样执行xcodebuild命令时,系统是如何确定使用哪个路径下的Command Lines Tool工具包中的xcodebuild指令呢?
我们通过otool -tV /usr/bin/xcodebuild看到,在它的代码段中包含了_xcselect_invoke_xcrun命令调用。
libxcselect.dylib 👇🏻 _xcselect_invoke_xcrun 👇🏻 libxcrun.dylib 👇🏻 xcrun_main
据调用栈,它的底层是调用了xcrun。
等于实际调用方式是通过xcode-select获取工具包路径,然后执行该工具包下的命令行工具。
所以下面两个是等价的:
xcrun xcodebuild xcodebuild 另外相关命令: xcrun --find clang // 找到指定工具路径 xcrun --sdk iphoneos --find pngcrush xcrun --sdk macosx --show-sdk-path
构建相关
平时常用于编写构建脚本,持续集成使用的命令行工具。
xcodebuild
xcodebuild类似GNU里的make,它是一套完整的编译工具。
苹果做了很多简化编译的操作,使得开发者不需要像使用make一样编写makefile,仅需根据实际情况指定workspace、project、target、scheme即可完成工程的编译。
主要功能有:
1、build:构建(编译),生成build目录,将构建过程中的文件存放在这个目录下。
2、clean:清除build目录下的文件
3、test:测试某个scheme,scheme必须指定
4、archive:执行archive,导出ipa包
5、analyze:执行analyze操作
# 清理 xcodebuild clean -workspace ${WORKSPACE_PATH} -scheme ${SCHEME_NAME} -configuration ${BUILD_TYPE} # 构建 xcodebuild archive -workspace ${WORKSPACE_PATH} -scheme ${SCHEME_NAME} -archivePath ${ARCHIVE_PATH} ## 存档 xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath ${IPA_PATH} -exportOptionsPlist ${EXPORTOPTIONSPLIST_PATH} xctool 是 facebook 推出的用于替换 xcodebuild 的更易于测试 iOS 和 mac 应用程序的命令行工具,特别适用于 iOS App 的持续集成;
altool
用于验证 ipa 以及上传 ipa 到 Store。
# 验证 # version、build号是否正确等case xcrun altool --validate-app -f xxx.ipa -t ios --apiKey xxx --apiIssuer xxx --verbose # 上传 xcrun altool --upload-app -f xxx.ipa -t ios --apiKey xxx --apiIssuer xxx --verbose
symbol符号相关
常用与符号化崩溃日志,XCode中的配置格式DWARF 与 dSYM。
DWARF是文件格式
dSYM是APP的符号文件,crash时用于还原崩溃日志中的符号地址。
打包时,Build Settings -> Debug Information Format设置默认
Debug: DWARF 调试信息存储在app中便于调试
Release: DWARF With dSYM File 调试信息与APP分离,单独放在一个文件中
dwarfdump
DWARF格式文件的工具,用于解析,查看dsym文件用。
# 查看 xx.app 文件的 UUID dwarfdump --uuid xx.app/xx # 查看 xx.app.dSYM 文件的 UUID dwarfdump --uuid xx.app.dSYM # 导出debug_info 的信息到文件 debug_line.txt 中 dwarfdump --debug-info xx.app.dSYM > debug_info.txt
dsymutil
从可执行二进制中 中提取 dSYM 文件(如果已经分离了,提取为空),对 dSYM 文件进行一些操作。
# 从二进制文件中还有`DSYM`信息的二进制包中抽取形成`.dysm`文件
dsymutil XXX
symbolicatecrash
是一个perl脚本,用于Crash 文件符号化
# 需要先添加环境变量,不然会报错 export DEVELOPER_DIR="/Applications/XCode.App/Contents/Developer" # 运行命令前需要将崩溃日志、 dSYM 以及 symbolicatecrash 复制到同一个目录下 symbolicatecrash log.crash -d xxx.app.dSYM > symbol.log
atos
Crash 单独符号化 #5 Demo 0x100f1fcfc 0x100e9c000 + 539900 #5 Demo 0xA 0xB + 539900 # 0x0000000B为 load address; # 0x0000000A为 symbol address # 最后一个i表示显示内联函数 atos -arch arm64 -o TestDemo.app.dSYM/Contents/Resources/DWARF/TestDemo -l 0x0000000B 0x0000000A -i
Mach-O 操作相关
Mach-O文件是Mac、iOS系统的多种文件保存格式,如:.o文件,exe可执行文件等。通过了解Mach-O文件的组成有利于对产物的更清楚的掌握。
关于 Mach-O 操作的大部分工具都是 LLVM 下面的,包括otool、objdump、nm、dwarfdump等等,其命令本质上都是一个替身,背后实际上都是llvm-XXX命令的原身。
nm
nm 命令是 Mach-O 文件分析工具,用于查看符号表, 这里说的符号指的是类名,方法名,有地址与之对应的。
# 得到XXX中的程序符号表 nm XXX # 查看所有符号,会打印出符号来源哪个地方 nm -nm XXX # 找到未定义的符号,也就是外部符号 nm -u XXX 符号的修饰符意义如下: A 该符号的值在今后的链接中将不再改变; B 该符号放在 BSS 段中,通常是那些未初始化的全局变量; D 该符号放在普通的数据段中,通常是那些已经初始化的全局变量; T 该符号放在代码段中,通常是那些全局非静态函数; U 该符号未定义过,需要自其他对象文件中链接进来; W 未明确指定的弱链接符号;同链接的其他对象文件中有它的定义就用上,否则就用一个系统特别指定的默认值。
otool & objdump
otool本质上就是objdump的一层 wrapper,底层其实都是使用objdump的实现。
它们是针对目标文件的展示工具,用来发现应用中使用到了哪些系统库,调用了其中哪些方法,使用了库中哪些对象及属性。
MachOView是Mach-O分析的GUI工具。
otool
平时在文件夹中看看app里都有什么,通常是展示包内容,看到nib、plist、mobileprovision和各种图片资源等,而可执行文件无法直接看到,这里可以使用otool工具进行查看了
目标文件的展示工具,用来发现应用中使用到了哪些系统库,调用了其中哪些方法,使用了库中哪些对象及属性。
# 查看依赖库,使用到哪些动态库,一般是涉及到 /usr/lib/ /System/Library/Frameworks/ @rpath 这三个位置,如果没有自己的动态库,就没有后面的 @rpath otool -L XXX # 查看汇编码,通过汇编可以查到一些业务逻辑,做一下YY otool -tV XXX # 输出Object-C类结构以及定义的方法 otool -ov XXX # 查看头部内容 otool -h XXX # 查看该应用是否砸壳 # 看输出结果的cryptid参数,其中0:砸壳、1:未砸壳。 otool -l XXX | grep -B 2 crypt # 查看代码段起始地址 otool -l iOSTest.app.dSYM/Contents/Resources/DWARF/iOSTest | grep __TEXT -C 5 # 查看重定位符号表 otool -r XXX
objdump
# 查看mach-header objdump --macho -private-header XXX # 查看text段 objdump --macho -d XXX # 查看符号表 objdump --macho --syms XXX # 查看导出符号表 objdump --macho --exports-trie XXX # 查看间接符号表 objdump --macho --indirect-symbols XXX # 查看重定位符号表 objdump --macho --reloc XXX
strings
查看二进制文件中的字符串
# 查看指定字符串 strings XXX | grep "xxx"
lipo
lipo 是一个在 Mac OS X 中处理通用程序(Universal Binaries)的工具。可以对静态库中的多种架构进行拆包和合并。
### 查看查看静态库支持的 CPU 架构 lipo -info frameworkName.framework/frameworkName lipo -info frameworkName.a ### 合并静态库 lipo -create 静态库存放路径 1 静态库存放路径 2 ... -output 整合后存放的路径 lipo -create frameworkName-armv7.a frameworkName-armv7s.a frameworkName-i386.a -output frameworkName.a lipo -create frameworkNameOne.framework/frameworkNameOne frameworkNameTwo.framework/frameworkNameTwo -output frameworkName.framework ### 静态库拆分 lipo 静态库源文件路径 -thin CPU 架构名称 -output 拆分后文件存放路径 lipo libname.a -thin armv7 -output libname-armv7.a ### 擦除指定架构 lipo -remove XXX.a arm64 -output XXX.a
ar
常用于创建、修改静态库;
ar -x XXX -d 删除备存文件中的成员文件。 -m 变更成员文件在备存文件中的次序。 -p 显示备存文件中的成员文件内容。 -q 将问家附加在备存文件末端。 -r 将文件插入备存文件中。 -t 显示备存文件中所包含的文件。 -x 自备存文件中取出成员文件。
file
用于查看文件基本信息,如包含了哪些架构,静态库或动态库。
class-dump
与'otool -ov' 提供的信息相同,用于打印出Objective-C 运行时信息。它为类、类别和协议生成声明。
工具链相关
swiftc
swift 语言的编译前端,swiftc只是一个替身,原身是swift-frontend。
clang
oc 语言的编译前端。
工具相关
actool
对项目中 Assets 的文件进行压缩、处理,生成.car文件。
swift-demangle
Swift 中因为命名空间的原因,需要对类名进行mangle,通过demangle显示正确名称。
问题解决
场景A :分析Mach-O文件中是否包含某个字符串
1.查询是否包含debug info调试信息,有的话去除
dsymutil XXX
2.查询Mach-O中是否包含目标字符串
strings XXX | grep "xxx" strings Demo ->~/Desktop/DemoStrings.txt xcrun otool -v -s __TEXT __cstring Demo
参考文章:https://juejin.cn/post/7060142847609012255#heading-20