eathread_callstack_glibc.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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 <string.h>
  7. #include <pthread.h>
  8. #include <eathread/eathread_storage.h>
  9. #if EATHREAD_GLIBC_BACKTRACE_AVAILABLE
  10. #include <signal.h>
  11. #include <execinfo.h>
  12. #endif
  13. namespace EA
  14. {
  15. namespace Thread
  16. {
  17. ///////////////////////////////////////////////////////////////////////////////
  18. // GetInstructionPointer
  19. //
  20. EATHREADLIB_API void GetInstructionPointer(void*& pInstruction)
  21. {
  22. pInstruction = __builtin_return_address(0);
  23. }
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // InitCallstack
  26. //
  27. EATHREADLIB_API void InitCallstack()
  28. {
  29. }
  30. ///////////////////////////////////////////////////////////////////////////////
  31. // ShutdownCallstack
  32. //
  33. EATHREADLIB_API void ShutdownCallstack()
  34. {
  35. }
  36. ///////////////////////////////////////////////////////////////////////////////
  37. // GetCallstack
  38. //
  39. // Capture up to nReturnAddressArrayCapacity elements of the call stack,
  40. // or the whole callstack, whichever is smaller.
  41. //
  42. EATHREADLIB_API size_t GetCallstack(void* pReturnAddressArray[], size_t nReturnAddressArrayCapacity, const CallstackContext* pContext)
  43. {
  44. EA_UNUSED(pContext);
  45. #if EATHREAD_GLIBC_BACKTRACE_AVAILABLE
  46. size_t count = 0;
  47. // The pContext option is not currently supported.
  48. if(pContext == NULL)
  49. {
  50. count = (size_t)backtrace(pReturnAddressArray, (int)nReturnAddressArrayCapacity);
  51. if(count > 0)
  52. {
  53. --count; // Remove the first entry, because it refers to this function and by design we don't include this function.
  54. memmove(pReturnAddressArray, pReturnAddressArray + 1, count * sizeof(void*));
  55. }
  56. }
  57. return count;
  58. #elif defined(EA_PLATFORM_APPLE) && defined(EA_PROCESSOR_X86)
  59. // Apple's ABI defines a callstack frame system.
  60. // http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/100-32-bit_PowerPC_Function_Calling_Conventions/32bitPowerPC.html#//apple_ref/doc/uid/TP40002438-SW20
  61. // Apple x86 stack frame:
  62. // struct StackFrame {
  63. // StackFrame* mpParentStackFrame;
  64. // void* mpParentCR;
  65. // void* mpReturnPC;
  66. // }
  67. //
  68. //struct StackFrame { To do: Re-write this in terms of StackFrame and pContext.
  69. // StackFrame* mpParentStackFrame;
  70. // void* mpParentCR;
  71. // void* mpReturnPC;
  72. //};
  73. size_t index = 0;
  74. if(nReturnAddressArrayCapacity)
  75. {
  76. void* fpParent = __builtin_frame_address(1); // frame pointer of caller.
  77. void** fp;
  78. pReturnAddressArray[index++] = __builtin_return_address(0);
  79. fp = (void**)fpParent;
  80. while(fp && *fp && (index < nReturnAddressArrayCapacity))
  81. {
  82. fpParent = *fp;
  83. fp = fpParent;
  84. if(*fp)
  85. pReturnAddressArray[index++] = *(fp + 2);
  86. }
  87. }
  88. return index;
  89. #else
  90. EA_UNUSED(pReturnAddressArray);
  91. EA_UNUSED(nReturnAddressArrayCapacity);
  92. return 0;
  93. #endif
  94. }
  95. ///////////////////////////////////////////////////////////////////////////////
  96. // GetCallstackContext
  97. //
  98. EATHREADLIB_API void GetCallstackContext(CallstackContext& context, const Context* pContext)
  99. {
  100. #if defined(EA_PROCESSOR_X86_64)
  101. context.mRIP = pContext->Rip;
  102. context.mRSP = pContext->Rsp;
  103. context.mRBP = pContext->Rbp;
  104. #elif defined(EA_PROCESSOR_X86)
  105. context.mEIP = pContext->Eip;
  106. context.mESP = pContext->Esp;
  107. context.mEBP = pContext->Ebp;
  108. #elif defined(EA_PROCESSOR_ARM)
  109. context.mSP = pContext->mGpr[13];
  110. context.mLR = pContext->mGpr[14];
  111. context.mPC = pContext->mGpr[15];
  112. #else
  113. // To do.
  114. #endif
  115. }
  116. ///////////////////////////////////////////////////////////////////////////////
  117. // GetModuleFromAddress
  118. //
  119. EATHREADLIB_API size_t GetModuleFromAddress(const void* /*address*/, char* pModuleName, size_t /*moduleNameCapacity*/)
  120. {
  121. // Not currently implemented for the given platform.
  122. pModuleName[0] = 0;
  123. return 0;
  124. }
  125. ///////////////////////////////////////////////////////////////////////////////
  126. // GetModuleHandleFromAddress
  127. //
  128. EATHREADLIB_API ModuleHandle GetModuleHandleFromAddress(const void* /*pAddress*/)
  129. {
  130. // Not currently implemented for the given platform.
  131. return 0;
  132. }
  133. ///////////////////////////////////////////////////////////////////////////////
  134. // GetCallstackContext
  135. //
  136. // Under Windows, the threadId parameter is expected to be a thread HANDLE,
  137. // which is different from a windows integer thread id.
  138. // On Unix the threadId parameter is expected to be a pthread id.
  139. //
  140. EATHREADLIB_API bool GetCallstackContext(CallstackContext& context, intptr_t /*threadId*/)
  141. {
  142. //if(threadId == pthread_self()) // Note that at least for MacOS, it's possible to get other threads' info.
  143. {
  144. #if defined(EA_PROCESSOR_X86)
  145. context.mEIP = (uint32_t)__builtin_return_address(0);
  146. context.mESP = (uint32_t)__builtin_frame_address(1);
  147. context.mEBP = 0;
  148. #else
  149. // To do.
  150. #endif
  151. return true;
  152. }
  153. // Not currently implemented for the given platform.
  154. memset(&context, 0, sizeof(context));
  155. return false;
  156. }
  157. ///////////////////////////////////////////////////////////////////////////////
  158. // GetCallstackContextSysThreadId
  159. //
  160. EATHREADLIB_API bool GetCallstackContextSysThreadId(CallstackContext& context, intptr_t sysThreadId)
  161. {
  162. return GetCallstackContext(context, sysThreadId);
  163. }
  164. // To do: Remove the usage of sStackBase for the platforms that it's not needed,
  165. // as can be seen from the logic below. For example Mac OSX probably doesn't need it.
  166. static EA::Thread::ThreadLocalStorage sStackBase;
  167. ///////////////////////////////////////////////////////////////////////////////
  168. // SetStackBase
  169. //
  170. EATHREADLIB_API void SetStackBase(void* pStackBase)
  171. {
  172. if(pStackBase)
  173. sStackBase.SetValue(pStackBase);
  174. else
  175. {
  176. pStackBase = __builtin_frame_address(0);
  177. if(pStackBase)
  178. SetStackBase(pStackBase);
  179. // Else failure; do nothing.
  180. }
  181. }
  182. ///////////////////////////////////////////////////////////////////////////////
  183. // GetStackBase
  184. //
  185. EATHREADLIB_API void* GetStackBase()
  186. {
  187. #if defined(EA_PLATFORM_UNIX)
  188. void* pBase;
  189. if(GetPthreadStackInfo(&pBase, NULL))
  190. return pBase;
  191. #endif
  192. // Else we require the user to have set this previously, usually via a call
  193. // to SetStackBase() in the start function of this currently executing
  194. // thread (or main for the main thread).
  195. return sStackBase.GetValue();
  196. }
  197. ///////////////////////////////////////////////////////////////////////////////
  198. // GetStackLimit
  199. //
  200. EATHREADLIB_API void* GetStackLimit()
  201. {
  202. #if defined(EA_PLATFORM_UNIX)
  203. void* pLimit;
  204. if(GetPthreadStackInfo(NULL, &pLimit))
  205. return pLimit;
  206. #endif
  207. // If this fails then we might have an issue where you are using GCC but not
  208. // using the GCC standard library glibc. Or maybe glibc doesn't support
  209. // __builtin_frame_address on this platform. Or maybe you aren't using GCC but
  210. // rather a compiler that masquerades as GCC (common situation).
  211. void* pStack = __builtin_frame_address(0);
  212. return (void*)((uintptr_t)pStack & ~4095); // Round down to nearest page, as the stack grows downward.
  213. }
  214. } // namespace Thread
  215. } // namespace EA