eathread_callstack_arm.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <eathread/eathread_callstack.h>
  5. #include <eathread/eathread_callstack_context.h>
  6. #include <eathread/eathread_storage.h>
  7. #include <string.h>
  8. #if EATHREAD_DEBUG_DETAIL_ENABLED
  9. #include <EAStdC/EASprintf.h>
  10. #endif
  11. #if defined(EA_PLATFORM_WINDOWS) && EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
  12. EA_DISABLE_ALL_VC_WARNINGS()
  13. #include <Windows.h>
  14. #include <winternl.h>
  15. EA_RESTORE_ALL_VC_WARNINGS()
  16. #endif
  17. #if defined(EA_PLATFORM_UNIX)
  18. #include <pthread.h>
  19. #include <eathread/eathread.h>
  20. #endif
  21. #if defined(EA_COMPILER_CLANG)
  22. #include <unwind.h>
  23. #endif
  24. namespace EA
  25. {
  26. namespace Thread
  27. {
  28. #if defined(EA_PLATFORM_WINDOWS) && EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
  29. EATHREADLIB_API void GetInstructionPointer(void*& pInstruction)
  30. {
  31. CONTEXT context;
  32. // Apparently there is no need to memset the context struct.
  33. context.ContextFlags = CONTEXT_ALL;
  34. RtlCaptureContext(&context);
  35. // Possibly use the __emit intrinsic. http://msdn.microsoft.com/en-us/library/ms933778.aspx
  36. pInstruction = (void*)(uintptr_t)context.___; // To do.
  37. }
  38. #elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
  39. EATHREADLIB_API void GetInstructionPointer(void*& pInstruction)
  40. {
  41. // __builtin_return_address returns the address with the Thumb bit set
  42. // if it's a return to Thumb code. We intentionally preserve this and
  43. // don't try to mask it away.
  44. pInstruction = (void*)(uintptr_t)__builtin_return_address(0);
  45. }
  46. #else
  47. EATHREADLIB_API void GetInstructionPointer(void*& /*pInstruction*/)
  48. {
  49. //Un-implemented
  50. }
  51. #endif
  52. ///////////////////////////////////////////////////////////////////////////////
  53. // InitCallstack
  54. //
  55. EATHREADLIB_API void InitCallstack()
  56. {
  57. }
  58. ///////////////////////////////////////////////////////////////////////////////
  59. // ShutdownCallstack
  60. //
  61. EATHREADLIB_API void ShutdownCallstack()
  62. {
  63. }
  64. #if defined(EA_PLATFORM_APPLE)
  65. // Apple defines a different ABI than the ARM eabi used by Linux and the ABI used
  66. // by Microsoft. It implements a predictable stack frame system using r7 as the
  67. // frame pointer. Documentation:
  68. // http://developer.apple.com/library/ios/#documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html
  69. //
  70. // Apple ARM stack frame:
  71. // struct StackFrame {
  72. // StackFrame* mpParentStackFrame;
  73. // void* mpReturnPC;
  74. // }
  75. //
  76. // Basically, Apple uses r7 as a frame pointer. So for any function you are
  77. // executing, r7 + 4 is the LR passed to us by the caller and is the PC of
  78. // the parent. And r7 + 0 is a pointer to the parent's r7.
  79. //
  80. static size_t GetCallstackARMApple(void* pReturnAddressArray[], size_t nReturnAddressArrayCapacity, const CallstackContext* pContext)
  81. {
  82. struct StackFrame {
  83. StackFrame* mpParentStackFrame;
  84. void* mpReturnPC;
  85. };
  86. size_t index = 0;
  87. if(nReturnAddressArrayCapacity && pContext->mFP) // To consider: Do some basic validation of mFP if it refers to this same thread.
  88. {
  89. StackFrame* pStackFrame = static_cast<StackFrame*>((void*)pContext->mFP); // Points to the GetCallstack frame pointer.
  90. pReturnAddressArray[index++] = pStackFrame->mpReturnPC; // Should happen to be equal to pContext->mLR.
  91. while(pStackFrame && pStackFrame->mpReturnPC && (index < nReturnAddressArrayCapacity)) // To consider: do some validation of the PC. We can validate it by making sure it's with 20 MB of our PC and also verify that the instruction before it (be it Thumb or ARM) is a BL or BLX function call instruction.
  92. {
  93. pStackFrame = pStackFrame->mpParentStackFrame;
  94. if(pStackFrame && pStackFrame->mpReturnPC)
  95. pReturnAddressArray[index++] = pStackFrame->mpReturnPC;
  96. }
  97. }
  98. return index;
  99. }
  100. #endif
  101. #if defined(EA_COMPILER_CLANG)
  102. struct CallstackState
  103. {
  104. void** current;
  105. void** end;
  106. };
  107. static _Unwind_Reason_Code UnwindCallback(struct _Unwind_Context* context, void* arg)
  108. {
  109. CallstackState* state = static_cast<CallstackState*>(arg);
  110. uintptr_t pc = _Unwind_GetIP(context);
  111. if (pc)
  112. {
  113. if (state->current == state->end)
  114. {
  115. return _URC_END_OF_STACK;
  116. }
  117. else
  118. {
  119. *state->current++ = reinterpret_cast<void*>(pc);
  120. }
  121. }
  122. return _URC_NO_REASON;
  123. }
  124. #endif
  125. ///////////////////////////////////////////////////////////////////////////////
  126. // GetCallstack
  127. //
  128. // Capture up to nReturnAddressArrayCapacity elements of the call stack,
  129. // or the whole callstack, whichever is smaller.
  130. ///////////////////////////////////////////////////////////////////////////////
  131. EATHREADLIB_API size_t GetCallstack(void* pReturnAddressArray[], size_t nReturnAddressArrayCapacity, const CallstackContext* pContext)
  132. {
  133. void* p;
  134. CallstackContext context;
  135. size_t entryCount = 0;
  136. if(pContext)
  137. context = *pContext;
  138. else
  139. {
  140. #if defined(EA_COMPILER_ARM)
  141. context.mFP = 0; // We don't currently have a simple way to read fp (which is r7 (Thumb) or r11 (ARM)).
  142. context.mSP = (uintptr_t)__current_sp();
  143. context.mLR = (uintptr_t)__return_address();
  144. GetInstructionPointer(p); // Intentionally don't call __current_pc() or EAGetInstructionPointer, because these won't set the Thumb bit it this is Thumb code.
  145. context.mPC = (uintptr_t)p;
  146. #elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG) // Including Apple iOS.
  147. void* spAddress = &context.mSP;
  148. void* sp;
  149. asm volatile(
  150. "add %0, sp, #0\n"
  151. "str %0, [%1, #0]\n"
  152. : "=r"(sp), "+r"(spAddress) :: "memory");
  153. context.mFP = (uintptr_t)__builtin_frame_address(0);
  154. context.mLR = (uintptr_t)__builtin_return_address(0);
  155. GetInstructionPointer(p); // Intentionally don't call EAGetInstructionPointer, because it won't set the Thumb bit it this is Thumb code.
  156. context.mPC = (uintptr_t)p;
  157. #elif defined(EA_PLATFORM_WINDOWS) && EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
  158. // Possibly use the __emit intrinsic. Do this by making a __declspec(naked) function that
  159. // does nothing but return r14 (move r14 to r0). Need to know the opcode for that.
  160. // http://msdn.microsoft.com/en-us/library/ms933778.aspx
  161. #error Need to complete this somehow.
  162. context.mFP = 0;
  163. context.mLR = 0;
  164. context.mSP = 0;
  165. GetInstructionPointer(p); // Intentionally don't call EAGetInstructionPointer, because it won't set the Thumb bit it this is Thumb code.
  166. context.mPC = (uintptr_t)p;
  167. #endif
  168. }
  169. #if defined(EA_PLATFORM_APPLE)
  170. // We have reason to believe that the following should be reliable. But if it's not then we should
  171. // just call the code below.
  172. entryCount = GetCallstackARMApple(pReturnAddressArray, nReturnAddressArrayCapacity, &context);
  173. if(entryCount >= 3) // If GetCallstackARMApple seems to have been successful, use it. Else fall through to the more complicated code below.
  174. return entryCount;
  175. #elif defined(EA_COMPILER_CLANG)
  176. CallstackState state = { pReturnAddressArray, pReturnAddressArray + nReturnAddressArrayCapacity };
  177. _Unwind_Backtrace(UnwindCallback, &state);
  178. entryCount = state.current - pReturnAddressArray;
  179. #else
  180. EA_UNUSED(pReturnAddressArray);
  181. EA_UNUSED(nReturnAddressArrayCapacity);
  182. EA_UNUSED(context);
  183. #endif
  184. EA_UNUSED(p);
  185. return entryCount;
  186. }
  187. ///////////////////////////////////////////////////////////////////////////////
  188. // GetCallstackContext
  189. //
  190. EATHREADLIB_API void GetCallstackContext(CallstackContext& context, const Context* pContext)
  191. {
  192. context.mSP = pContext->mGpr[13];
  193. context.mLR = pContext->mGpr[14];
  194. context.mPC = pContext->mGpr[15];
  195. }
  196. ///////////////////////////////////////////////////////////////////////////////
  197. // GetModuleFromAddress
  198. //
  199. EATHREADLIB_API size_t GetModuleFromAddress(const void* /*address*/, char* pModuleName, size_t /*moduleNameCapacity*/)
  200. {
  201. pModuleName[0] = 0;
  202. return 0;
  203. }
  204. ///////////////////////////////////////////////////////////////////////////////
  205. // GetModuleHandleFromAddress
  206. //
  207. EATHREADLIB_API ModuleHandle GetModuleHandleFromAddress(const void* /*pAddress*/)
  208. {
  209. return 0;
  210. }
  211. ///////////////////////////////////////////////////////////////////////////////
  212. // GetCallstackContext
  213. //
  214. // Under Windows, the threadId parameter is expected to be a thread HANDLE,
  215. // which is different from a windows integer thread id.
  216. // On Unix the threadId parameter is expected to be a pthread id.
  217. //
  218. EATHREADLIB_API bool GetCallstackContext(CallstackContext& context, intptr_t threadId)
  219. {
  220. memset(&context, 0, sizeof(context));
  221. // True Linux-based ARM platforms (usually tablets and phones) can use pthread_attr_getstack.
  222. #if defined(EA_PLATFORM_ANDROID) || defined(EA_PLATFORM_IPHONE)
  223. if((threadId == (intptr_t)kThreadIdInvalid) ||
  224. (threadId == (intptr_t)kThreadIdCurrent) ||
  225. (threadId == (intptr_t)EA::Thread::GetThreadId()))
  226. {
  227. void* p;
  228. // TODO: make defines of this so that the implementation between us and GetCallstack remains the same
  229. #if defined(EA_COMPILER_ARM)
  230. context.mSP = (uint32_t)__current_sp();
  231. context.mLR = (uint32_t)__return_address();
  232. context.mPC = (uint32_t)__current_pc();
  233. #elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
  234. // register uintptr_t current_sp asm ("sp");
  235. p = __builtin_frame_address(0);
  236. context.mSP = (uintptr_t)p;
  237. p = __builtin_return_address(0);
  238. context.mLR = (uint32_t)p;
  239. EAGetInstructionPointer(p);
  240. context.mPC = reinterpret_cast<uintptr_t>(p);
  241. #elif defined(EA_COMPILER_MSVC)
  242. context.mSP = 0;
  243. #error EACallstack::GetCallstack: Need a way to get the return address (register 14)
  244. // Possibly use the __emit intrinsic. Do this by making a __declspec(naked) function that
  245. // does nothing but return r14 (move r14 to r0). Need to know the opcode for that.
  246. // http://msdn.microsoft.com/en-us/library/ms933778.aspx
  247. context.mLR = 0;
  248. EAGetInstructionPointer(p);
  249. context.mPC = reinterpret_cast<uintptr_t>(p);
  250. #endif
  251. context.mStackBase = (uintptr_t)GetStackBase();
  252. context.mStackLimit = (uintptr_t)GetStackLimit();
  253. context.mStackPointer = context.mSP;
  254. return true;
  255. }
  256. // Else haven't implemented getting the stack info for other threads
  257. #else
  258. // Not currently implemented for the given platform.
  259. EA_UNUSED(threadId);
  260. #endif
  261. return false;
  262. }
  263. ///////////////////////////////////////////////////////////////////////////////
  264. // GetCallstackContextSysThreadId
  265. //
  266. EATHREADLIB_API bool GetCallstackContextSysThreadId(CallstackContext& context, intptr_t sysThreadId)
  267. {
  268. return GetCallstackContext(context, sysThreadId);
  269. }
  270. // To do: Remove the usage of sStackBase for the platforms that it's not needed,
  271. // as can be seen from the logic below. For example iPhone probably doesn't need it.
  272. EA::Thread::ThreadLocalStorage sStackBase;
  273. ///////////////////////////////////////////////////////////////////////////////
  274. // SetStackBase
  275. //
  276. EATHREADLIB_API void SetStackBase(void* pStackBase)
  277. {
  278. if(pStackBase)
  279. sStackBase.SetValue(pStackBase);
  280. else
  281. {
  282. // Can't call GetStackLimit() because doing so would disturb the stack.
  283. // As of this writing, we don't have an EAGetStackTop macro which could do this.
  284. // So we implement it inline here.
  285. #if defined(EA_COMPILER_ARM)
  286. pStackBase = (void*)__current_sp();
  287. #elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
  288. pStackBase = __builtin_frame_address(0);
  289. #endif
  290. if(pStackBase)
  291. SetStackBase(pStackBase);
  292. // Else failure; do nothing.
  293. }
  294. }
  295. ///////////////////////////////////////////////////////////////////////////////
  296. // GetStackBase
  297. //
  298. EATHREADLIB_API void* GetStackBase()
  299. {
  300. #if defined(EA_PLATFORM_UNIX)
  301. void* pBase;
  302. if(GetPthreadStackInfo(&pBase, NULL))
  303. return pBase;
  304. #endif
  305. // Else we require the user to have set this previously, usually via a call
  306. // to SetStackBase() in the start function of this currently executing
  307. // thread (or main for the main thread).
  308. return sStackBase.GetValue();
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////
  311. // GetStackLimit
  312. //
  313. EATHREADLIB_API void* GetStackLimit()
  314. {
  315. #if defined(EA_PLATFORM_UNIX)
  316. void* pLimit;
  317. if(GetPthreadStackInfo(NULL, &pLimit))
  318. return pLimit;
  319. #endif
  320. #if defined(EA_COMPILER_ARM)
  321. void* pStack = (void*)__current_sp();
  322. #elif defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)
  323. void* pStack = __builtin_frame_address(0);
  324. #else
  325. void* pStack = NULL; // TODO: determine fix.
  326. pStack = &pStack;
  327. #endif
  328. return (void*)((uintptr_t)pStack & ~4095); // Round down to nearest page, as the stack grows downward.
  329. }
  330. } // namespace Thread
  331. } // namespace EA