iOS中线程Call Stack的捕获和解析(一)

本文介绍如何获取并解析iOS线程的Call Stack,包括基础结构、指令指针和基址指针、线程执行状态、不同平台的寄存器以及算法实现。通过这些知识,可以实现类似Xcode调试时的暂停效果。
摘要由CSDN通过智能技术生成

http://blog.csdn.net/jasonblog/article/details/49909209这里对上个月做的一个技术项目做部分技术小结,这篇文章描述的功能和我们在使用Xcode进行调试时点击暂停的效果类似。

一、获取任意一个线程的Call Stack

如果要获取当前线程的调用栈,可以直接使用现有API:[NSThread callStackSymbols]

但是并没有相关API支持获取任意线程的调用栈,所以只能自己编码实现。

1. 基础结构

一个线程的调用栈是什么样的呢?

我的理解是应该包含当前线程的执行地址,并且从这个地址可以一级一级回溯到线程的入口地址,这样就反向构成了一条链:线程入口执行某个方法,然后逐级嵌套调用到当前现场。

Call_stack_layout_svg(图片来源于维基百科)

如图所示,每一级的方法调用,都对应了一张活动记录,也称为活动帧。也就是说,调用栈是由一张张帧结构组成的,可以称之为栈帧。

我们可以看到,一张栈帧结构中包含着Return Address,也就是当前活动记录执行结束后要返回的地址(展开)。

那么,在我们获取到栈帧后,就可以通过返回地址来进行回溯了。

2. 指令指针和基址指针

我们明确了两个目标:(1)当前执行的指令,(2)当前栈帧结构。

以x86为例,寄存器用途如下:

SP/ESP/RSP: Stack pointer for top address of the stack.
BP/EBP/RBP: Stack base pointer for holding the address of the current stack frame.
IP/EIP/RIP: Instruction pointer. Holds the program counter, the current instruction address.

可以看到,我们可以通过指令指针来获取当前指令地址,以及通过栈基址指针获取当前栈帧地址。

那么问题来了,我们怎么获取到相关寄存器呢?

3. 线程执行状态

考虑到一个线程被挂起时,后续继续执行需要恢复现场,所以在挂起时相关现场需要被保存起来,比如当前执行到哪条指令了。

那么就要有相关的结构体来为线程保存运行时的状态,经过一番查阅,得到如下信息:

The function thread_get_state returns the execution state (e.g. the machine registers) of target_thread as specified by flavor.

Function - Return the execution state for a thread.

SYNOPSIS

kern_return_t   thread_get_state
                (thread_act_t                     target_thread,
                 thread_state_flavor_t                   flavor,
                 thread_state_t                       old_state,
                 mach_msg_type_number_t         old_state_count);
/*
 * THREAD_STATE_FLAVOR_LIST 0
 *  these are the supported flavors
 */
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值