2015-10-15 80 views
2

的方式来获得帧指针

enter image description here如何获取iOS中任意线程的正确帧指针?

在对iPhone 5S设备/ Xcode的7运行的演示应用,我就先用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;,根据苹果文件(ARMv6ARM64),

寄存器R7用作帧指针的ARMv6

同时ARM64

帧指针寄存器(X29)X29必须始终寻址有效帧记录,虽然某些功能 - 如叶子函数或尾部调用 - 可以选择不在此列表中创建条目。因此,即使没有调试信息,堆栈跟踪也将始终有意义。

_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 */ 
}; 

的方式来证明帧指针是错误的

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

  1. 如果参数是当前线程,mach_thread_self()例如,FP始终为0,这是从__builtin_frame_address(0)不同;

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

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

什么让我困惑

Apple Doc帧指针寄存器(X29)必须解决一个有效的框架纪录,但我可以读取它ZERO值。

此外,ARM Doc状态在过程调用标准的所有变体中,寄存器r16,r17,r29和r30都有特殊的作用。在用于保存地址时,这些角色 被标记为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调用堆栈。再次

Getting a backtrace of other thread

How To Loop Through All Active Thread in iPad app

Printing a stack trace from another thread

感谢:

在此之前,我读过这些链接。

更新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)

UPDATE 3

由同事的启发,我试图联汇编,并使其在i386:

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

uintptr_t builtinFP = (uintptr_t)__builtin_frame_address(0); 

现在ebp变量保存相同的值来builtinFP的。但如何在任意线程上执行此操作?

回答

1

我发现这个问题最终

- (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

我误解了宏观MACHINE_THREAD_STATE,这给了我是不同架构的普遍意义。