2015-10-15 83 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,這給了我是不同架構的普遍意義。