iOS 获取堆栈原理

455 阅读2分钟

前言

  1. [NSThread callStackSymbols]只能获取当前线程的调用栈,无法获取其他线程的调用栈
  2. 获取所有线程的调用栈,主要参考自KSCrash这个框架。有能力的同学可以深入研究一下

正文开始

步骤

image.png 一、获取函数地址

通过task_threads获取所有线程,并通过thread_get_state获取线程调用栈,进而获取当前线程所有的函数地址

二、定位镜像

  1. dyld提供了镜像相关的接口,如获取镜像数量_dyld_image_count、名称_dyld_get_image_name及其地址_dyld_get_image_header,通过镜像地址就可以获取Mach-O相关的信息
  2. Mach-O中的Mach64 Header中包含了Load Commands数量,Load Commands加载命令中包含了LC_SEGMENT_64,该加载命令数据结构包含了命令名称Command、虚拟地址VM Address及其大小VM Size,因此可以通过遍历获取LC_SEGMENT_64中的各个段的虚拟起始地址及其范围,就可以比较来定位是否在该段中,进而就可以确定是否在该镜像中

三、查找符号

通过LC_SYMTAB加载命令获取符号表及字符串表的信息,如地址、数量及大小,就可以获取符号表中的所有符号及字符串表中对应的函数名称

四、定位符号

通过遍历符号表中的所有符号地址来匹配与当前函数地址最接近的,即为要寻找的函数符号,并通过符号表中的String Table Index字符串表偏移量来获取函数符号名称

参考资料

  1. iOS获取任意线程调用栈
  2. 一文读懂iOS线程调用栈原理
  3. iOS获取任意线程调用栈
  4. 获取任意线程的调用栈