如何获得iOS中的任意线程的正确的帧指针?

获取帧指针的方法

在这里输入图像说明

在iPhone 5s Device / Xcode 7上运行的Demo App上,我尝试使用thread_get_state获取任意线程的frame pointer ,但总是导致错误:

 - (BOOL)fillThreadState:(thread_t)thread intoMachineContext:(_STRUCT_MCONTEXT *)machineContext { mach_msg_type_number_t state_count = MACHINE_THREAD_STATE_COUNT; kern_return_t kr = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)&machineContext->__ss, &state_count); if (kr != KERN_SUCCESS) { char *str = mach_error_string(kr); printf("%s\n", str); return NO; } return YES; } 

我读这样的帧指针: uintptr_t fp = machineContext.__ss.__fp; ,根据苹果文件( ARMv6和ARM64 ),

寄存器R7被用作ARMv6上的帧指针

而ARM64上的x29

帧指针寄存器(x29)必须总是寻址一个有效的帧logging,尽pipe一些函数(如叶函数或尾调用)可能会select不在此列表中创build一个条目。 因此,即使没有debugging信息,堆栈跟踪也将始终有意义。

 _STRUCT_ARM_THREAD_STATE64 { __uint64_t __x[29]; /* General purpose registers x0-x28 */ __uint64_t __fp; /* Frame pointer x29 */ __uint64_t __lr; /* Link register x30 */ __uint64_t __sp; /* Stack pointer x31 */ __uint64_t __pc; /* Program counter */ __uint32_t __cpsr; /* Current program status register */ __uint32_t __pad; /* Same size for 32-bit or 64-bit clients */ }; 

certificate帧指针的方法是错误的

如何certificatefp( machineContext.__ss.__fp )不是一个正确的帧指针?

  1. 如果参数是当前线程mach_thread_self(),则fp始终为0 ,与__builtin_frame_address(0)

  2. 如果参数不是当前线程,例如主线程,则指向前一帧fp帧指针的指针将在两帧或三帧中为空,这对于正常的栈帧链表来说太短了;

  3. 仍然不是当前的线程,我sleep之前打印出主线程上使用backtrace的调用堆栈地址。 然后在另一个线程中,我挂起主线程并使用thread_get_state读取帧指针来thread_get_state调用堆栈,两个回溯缓冲区完全不同;

什么使我困惑

Apple Doc说帧指针寄存器(x29)必须总是处理有效的帧logging ,但是我可以从中读取一个ZERO值。

此外, ARM Doc指出,在过程调用标准的所有变体中,寄存器r16,r17,r29和r30都有特殊的作用。 在这些angular色中,当用于保存地址时,它们被标记为IP0,IP1,FP和LR

以下是_STRUCT_MCONTEXT值的一部分示例:

 Printing description of machineContext: (__darwin_mcontext64) machineContext = { __es = (__far = 0, __esr = 0, __exception = 0) __ss = { __x = { [0] = 292057776134 [1] = 6142843584 [2] = 3 [3] = 40 [4] = 624 [5] = 17923 [6] = 0 [7] = 0 [8] = 3968 [9] = 4294966207 [10] = 3603 [11] = 70 [12] = 0 [13] = 33332794515418112 [14] = 0 [15] = 4294967295 [16] = 4294967284 [17] = 18446744073709551585 [18] = 4295035980 [19] = 0 [20] = 0 [21] = 0 [22] = 17923 [23] = 624 [24] = 6142843584 [25] = 3 [26] = 40 [27] = 3 [28] = 0 } __fp = 0 __lr = 6142843568 __sp = 6877072044 __pc = 6142843488 __cpsr = 2582105136 __pad = 1 } __ns = { 

我在找什么

我现在正在寻找一种方法来获得任意线程的Frame Pointer的正确值

谢谢你的帮助!

更新1

当然,我想要的是得到任意线程的叶堆栈帧的正确的Frame Pointer ,然后沿着Frame pointerPrevious Pointer行进调用堆栈。

在此之前,我已经阅读了这些链接:

获取其他线程的回溯

如何通过iPad应用程序中的所有主动线程循环

从另一个线程打印堆栈跟踪

再次感谢。

更新2

我试过在其他平台上,但结果相同: 错误的帧指针

 - (uintptr_t)framePointerOfMachineContext:(_STRUCT_MCONTEXT *)machineContext { #if defined (__i386__) return machineContext->__ss.__ebp; #endif #if defined (__x86_64__) return machineContext->__ss.__rbp; #endif #if defined (__arm64__) return machineContext->__ss.__fp; #endif } 

framePointerOfMachineContext返回的值与__builtin_frame_address(0)

更新3

受到一位同事的启发,我尝试了内联,并在i386:

 uintptr_t ebp = 1; __asm__ ("mov %%ebp, %0;" :"=r"(ebp)); uintptr_t builtinFP = (uintptr_t)__builtin_frame_address(0); 

现在ebpvariables对于builtinFP具有相同的值。 但是如何在任意线程上执行此操作?

我最终发现了这个问题,

 - (BOOL)fillThreadState:(thread_t)thread intoMachineContext:(_STRUCT_MCONTEXT *)machineContext { mach_msg_type_number_t state_count = MACHINE_THREAD_STATE_COUNT; kern_return_t kr = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)&machineContext->__ss, &state_count); if (kr != KERN_SUCCESS) { char *str = mach_error_string(kr); printf("%s\n", str); return NO; } return YES; } 

thread_get_state很好,但参数应该是特定于体系结构的,比如x86_THREAD_STATE32x86_THREAD_STATE64等等。

我误解了macrosMACHINE_THREAD_STATE ,这给了我不同的体系结构的普遍意义。