eathread_callstack_apple.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <eathread/eathread.h>
  5. #include <eathread/eathread_futex.h>
  6. #include <eathread/eathread_storage.h>
  7. #include <eathread/eathread_callstack.h>
  8. #include <eathread/eathread_callstack_context.h>
  9. #include <eathread/apple/eathread_callstack_apple.h>
  10. #include <mach/thread_act.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <pthread.h>
  14. #include <dlfcn.h>
  15. #include <new>
  16. #if EATHREAD_APPLE_GETMODULEINFO_ENABLED
  17. #include <mach-o/dyld_images.h> //dyld_all_image_infos
  18. #include <mach-o/dyld.h> //segment_command(_64)
  19. #include <mach/task.h> //task_info
  20. #if defined(EA_PLATFORM_IPHONE)
  21. //On iPhone, this gets pulled in dynamically through libproc.dylib
  22. extern "C" int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize);
  23. #else
  24. #include <libproc.h> //proc_regionfilename
  25. #endif
  26. #endif
  27. #if EA_PLATFORM_PTR_SIZE == 8
  28. typedef struct mach_header_64 MachHeader;
  29. typedef struct segment_command_64 SegmentCommand;
  30. typedef struct section_64 Section;
  31. #define kLCSegment LC_SEGMENT_64
  32. #else
  33. typedef struct mach_header MachHeader;
  34. typedef struct segment_command SegmentCommand;
  35. typedef struct section Section;
  36. #define kLCSegment LC_SEGMENT
  37. #endif
  38. #if EACALLSTACK_GLIBC_BACKTRACE_AVAILABLE
  39. #include <signal.h>
  40. #include <execinfo.h>
  41. #endif
  42. namespace EA
  43. {
  44. namespace Thread
  45. {
  46. ///////////////////////////////////////////////////////////////////////////////
  47. // gModuleInfoApple
  48. //
  49. // We keep a cached array of the module info. It's possible that the module
  50. // info could change at runtime, though for our purposes the changes don't
  51. // usually matter. Nevertheless that's a limitation of this scheme and we
  52. // may need to do something about it in the future.
  53. // This global array is freed in ShutdownCallstack.
  54. // Currently this array is stored per-DLL when EAThread is built as a DLL.
  55. //
  56. static ModuleInfoApple* gModuleInfoAppleArray = NULL;
  57. static size_t gModuleInfoAppleArrayCount = 0;
  58. static Futex* gCallstackFutex = NULL;
  59. ///////////////////////////////////////////////////////////////////////////////
  60. // ReallocModuleInfoApple
  61. //
  62. // This is not a fully generic Realloc function. It currently reallocs only
  63. // to a greater size or to zero, which is fine for our purposes. The caller
  64. // of this function needs to be aware that the Realloc may fail and should
  65. // use gModuleInfoAppleArrayCount as the array count and not the value passed
  66. // to this function.
  67. //
  68. static ModuleInfoApple* ReallocModuleInfoApple(size_t newCount)
  69. {
  70. if(gCallstackFutex)
  71. gCallstackFutex->Lock();
  72. EA::Thread::Allocator* pAllocator = EA::Thread::GetAllocator();
  73. EAT_ASSERT_MSG(pAllocator != NULL, "EA::Thread::SetAllocator needs to be called on app startup.");
  74. if(pAllocator)
  75. {
  76. if(newCount > gModuleInfoAppleArrayCount) // If increasing in size...
  77. {
  78. size_t allocSize = sizeof(ModuleInfoApple) * newCount;
  79. void* allocMemory = pAllocator->Alloc(allocSize);
  80. if(allocMemory)
  81. {
  82. ModuleInfoApple* pNew = new(allocMemory) ModuleInfoApple[newCount]; // Placement new always succeeds.
  83. if(gModuleInfoAppleArray && gModuleInfoAppleArray)
  84. {
  85. // gModuleInfoAppleArrayCount is guaranteed to be < newCount for this memcpy.
  86. memcpy(pNew, gModuleInfoAppleArray, sizeof(ModuleInfoApple) * gModuleInfoAppleArrayCount);
  87. pAllocator->Free(gModuleInfoAppleArray);
  88. }
  89. gModuleInfoAppleArray = pNew;
  90. gModuleInfoAppleArrayCount = newCount;
  91. }
  92. // Else fall through and use the existing gModuleInfoAppleArray.
  93. }
  94. else if(newCount == 0) // If freeing...
  95. {
  96. if(gModuleInfoAppleArray)
  97. {
  98. pAllocator->Free(gModuleInfoAppleArray);
  99. gModuleInfoAppleArray = NULL;
  100. gModuleInfoAppleArrayCount = 0;
  101. }
  102. }
  103. // Else we do nothing for the case of requesting a newCount < gModuleInfoAppleArrayCount.
  104. }
  105. if(gCallstackFutex)
  106. gCallstackFutex->Unlock();
  107. return gModuleInfoAppleArray; // gModuleInfoAppleArrayCount indicates the capacity of this array.
  108. }
  109. #if EATHREAD_APPLE_GETMODULEINFO_ENABLED
  110. // This fills a moduleInfoApple object with the information from all of the segments listed in the given mach_header's segments, starting at the given currentSegmentPos. It also puts the pModulePath info the moduleInfoApple object, which is then push_back on the given array.
  111. //
  112. // The results are appended to pModuleInfoAppleArray up to its capacity
  113. // pTypeFilter is used to filter out segment types
  114. // pModulePath is the path corresponding to the given pMachHeader. It is assumed it is NullTerminated
  115. // currentSegmentPos is the starting segment we are iterating over
  116. // pMachHeader is the mach_header with all the segment information
  117. void CreateModuleInfoApple(ModuleInfoApple* pModuleInfoAppleArray, size_t arrayCapacity, size_t& requiredArraySize, size_t& arraySize,
  118. const char* pTypeFilter, const char* pModulePath, uintptr_t currentSegmentPos, const MachHeader* pMachHeader, intptr_t offset)
  119. {
  120. for(uint32_t i = 0; i < pMachHeader->ncmds; i++) // Look at each command, paying attention to LC_SEGMENT/LC_SEGMENT_64 (segment_command) commands.
  121. {
  122. const SegmentCommand* pSegmentCommand = reinterpret_cast<const SegmentCommand*>(currentSegmentPos); // This won't actually be a segment_command unless the type is kLCSegment
  123. if(pSegmentCommand != NULL && pSegmentCommand->cmd == kLCSegment) // If this really is a segment_command... (otherwise it is some other kind of command)
  124. {
  125. const size_t segnameBufferLen = sizeof(pSegmentCommand->segname) + 1;
  126. char segnameBuffer[segnameBufferLen];
  127. memcpy(segnameBuffer, pSegmentCommand->segname, sizeof(pSegmentCommand->segname));
  128. segnameBuffer[segnameBufferLen-1] = '\0'; // Incase segname was not 0-terminated
  129. if(!pTypeFilter || strncmp(segnameBuffer, pTypeFilter, sizeof(segnameBuffer)))
  130. {
  131. requiredArraySize++;
  132. if (arraySize < arrayCapacity)
  133. {
  134. ModuleInfoApple& info = pModuleInfoAppleArray[arraySize++];
  135. uint64_t uOffset = (uint64_t)offset;
  136. info.mBaseAddress = (uint64_t)(pSegmentCommand->vmaddr + uOffset);
  137. // info.mModuleHandle = reinterpret_cast<ModuleHandle>((uintptr_t)info.mBaseAddress);
  138. info.mSize = (uint64_t)pSegmentCommand->vmsize;
  139. // Copy modulePath to info.mPath.
  140. strlcpy(info.mPath, pModulePath, EAArrayCount(info.mPath));
  141. // Get the beginning of the file name within modulePath and copy the file name to info.mName.
  142. const char* pDirSeparator = strrchr(pModulePath, '/');
  143. if(pDirSeparator)
  144. pDirSeparator++;
  145. else
  146. pDirSeparator = pModulePath;
  147. strlcpy(info.mName, pDirSeparator, EAArrayCount(info.mName));
  148. info.mPermissions[0] = (pSegmentCommand->initprot & VM_PROT_READ) ? 'r' : '-';
  149. info.mPermissions[1] = (pSegmentCommand->initprot & VM_PROT_WRITE) ? 'w' : '-';
  150. info.mPermissions[2] = (pSegmentCommand->initprot & VM_PROT_EXECUTE) ? 'x' : '-';
  151. info.mPermissions[3] = '/';
  152. info.mPermissions[4] = (pSegmentCommand->maxprot & VM_PROT_READ) ? 'r' : '-';
  153. info.mPermissions[5] = (pSegmentCommand->maxprot & VM_PROT_WRITE) ? 'w' : '-';
  154. info.mPermissions[6] = (pSegmentCommand->maxprot & VM_PROT_EXECUTE) ? 'x' : '-';
  155. info.mPermissions[7] = '\0';
  156. strlcpy(info.mType,pSegmentCommand->segname,EAArrayCount(info.mType));
  157. //**********************************************************************************
  158. //For Debugging Purposes
  159. //__TEXT 0000000100000000-0000000100001000 [ 4K] r-x/rwx SM=COW /Build/Products/Debug/TestProject.app/Contents/MacOS/TestProject
  160. //printf("%20s %llx-%llx %s %s\n", segnameBuffer, (unsigned long long)info.mBaseAddress, (unsigned long long)(info.mBaseAddress + pSegmentCommand->vmsize), info.mPermissions, pModulePath);
  161. //**********************************************************************************/
  162. }
  163. }
  164. }
  165. currentSegmentPos += pSegmentCommand->cmdsize;
  166. }
  167. }
  168. #endif // EATHREAD_APPLE_GETMODULEINFO_ENABLED
  169. #if EATHREAD_APPLE_GETMODULEINFO_ENABLED
  170. // GetModuleInfoApple
  171. //
  172. // This function exists for the purpose of being a central module/VM map info collecting function,
  173. // used by a couple functions within EACallstack.
  174. //
  175. // We used to use vmmap and parse the output
  176. // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/vmmap.1.html
  177. // But starting ~osx 10.9 vmmap can not be called due to new security restrictions
  178. //
  179. // I tried using ::mach_vm_region, but I was unable to find the type of the segments (__TEXT, etc.)
  180. // and system libraries addresses were given, but their name/modulePath was not.
  181. // ::mach_vm_region_recurse did not solve this problem either.
  182. //
  183. // Replaced _dyld_get_all_image_infos() call with task_info() call as the old call is no longer available
  184. // with osx 10.13 (High Sierra).
  185. size_t GetModuleInfoApple(ModuleInfoApple* pModuleInfoAppleArray, size_t arrayCapacity,
  186. const char* pTypeFilter, bool bEnableCache)
  187. {
  188. // The following is present to handle the case that the user forgot to call EA::Thread::InitCallstack().
  189. // We don't match this with a ShutdownCallstack, and so the user might see memory leaks in that case.
  190. // The user should call EA::Thread::InitCallstack on app startup and EA::Thread::ShutdownCallstack on
  191. // app shutdown, at least if the user wants to use this function.
  192. if(!gCallstackFutex)
  193. InitCallstack();
  194. size_t requiredArraySize = 0;
  195. size_t arraySize = 0;
  196. if(bEnableCache)
  197. {
  198. if(gCallstackFutex)
  199. gCallstackFutex->Lock();
  200. if(gModuleInfoAppleArrayCount == 0) // If nothing is cached...
  201. {
  202. // Call ourselves recursively, for the sole purpose of getting the required size and filling the cache.
  203. // We call GetModuleInfoApple with a NULL filter (get all results). This may result in a required size that's
  204. // greater than the size needed for the user's possibly supplied filter. Thus we have a variable here
  205. // called maxRequiredArraySize.
  206. const size_t maxRequiredArraySize = GetModuleInfoApple(NULL, 0, NULL, false);
  207. ReallocModuleInfoApple(maxRequiredArraySize); // If the realloc fails, the code below deals with it safely.
  208. // Call ourselves recursively, for the purpose of filling in the cache.
  209. GetModuleInfoApple(gModuleInfoAppleArray, gModuleInfoAppleArrayCount, NULL, false);
  210. }
  211. // Copy our cache to the user's supplied array, while applying the filter and updating requiredArraySize.
  212. for(size_t i = 0, iEnd = gModuleInfoAppleArrayCount; i != iEnd; i++)
  213. {
  214. const ModuleInfoApple& mia = gModuleInfoAppleArray[i];
  215. if(!pTypeFilter || strstr(mia.mType, pTypeFilter)) // If the filter matches...
  216. {
  217. requiredArraySize++;
  218. if(arraySize < arrayCapacity) // If there is room in the user-supplied array...
  219. {
  220. ModuleInfoApple& miaUser = pModuleInfoAppleArray[arraySize++];
  221. memcpy(&miaUser, &mia, sizeof(ModuleInfoApple));
  222. }
  223. }
  224. }
  225. if(gCallstackFutex)
  226. gCallstackFutex->Unlock();
  227. }
  228. else
  229. {
  230. struct task_dyld_info t_info;
  231. uint32_t t_info_count = TASK_DYLD_INFO_COUNT;
  232. kern_return_t kr = task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&t_info, &t_info_count);
  233. if (kr != KERN_SUCCESS)
  234. {
  235. EAT_ASSERT_FORMATTED(false, "GetModuleInfoApple: task_info() returned %d", kr);
  236. return 0;
  237. }
  238. const struct dyld_all_image_infos* pAllImageInfos = (const struct dyld_all_image_infos *)t_info.all_image_info_addr;
  239. for(uint32_t i = 0; i < pAllImageInfos->infoArrayCount; i++)
  240. {
  241. const char* pModulePath = pAllImageInfos->infoArray[i].imageFilePath;
  242. if(pModulePath != NULL && strncmp(pModulePath, "", PATH_MAX) != 0)
  243. {
  244. uintptr_t currentSegmentPos = (uintptr_t)pAllImageInfos->infoArray[i].imageLoadAddress;
  245. const MachHeader* pMachHeader = reinterpret_cast<const MachHeader*>(currentSegmentPos);
  246. EAT_ASSERT(pMachHeader != NULL);
  247. currentSegmentPos += sizeof(*pMachHeader);
  248. // The system library addresses we obtain are the linker address.
  249. // So we need to get the get the dynamic loading offset
  250. // The offset is also stored in pAllImageInfos->sharedCacheSlide, but there is no way
  251. // to know whether or not it should get used on each image. (dyld and our executable images do not slide)
  252. // http://lists.apple.com/archives/darwin-kernel/2012/Apr/msg00012.html
  253. intptr_t offset = _dyld_get_image_vmaddr_slide(i);
  254. CreateModuleInfoApple(pModuleInfoAppleArray, arrayCapacity, requiredArraySize, arraySize,
  255. pTypeFilter, pModulePath, currentSegmentPos, pMachHeader, offset);
  256. }
  257. }
  258. // Iterating on dyld_all_image_infos->infoArray[] does not give us entries for /usr/lib/dyld.
  259. // We use the mach_header to get /usr/lib/dyld
  260. const MachHeader* pMachHeader = (const MachHeader*)pAllImageInfos->dyldImageLoadAddress;
  261. uintptr_t currentSegmentPos = (uintptr_t)pMachHeader + sizeof(*pMachHeader);
  262. char modulePath[PATH_MAX] = "";
  263. pid_t pid = getpid();
  264. int filenameLen = proc_regionfilename((int)pid,currentSegmentPos,modulePath,(uint32_t)sizeof(modulePath));
  265. EAT_ASSERT(filenameLen > 0 && modulePath != NULL && strncmp(modulePath,"",sizeof(modulePath)) != 0);
  266. if(filenameLen > 0)
  267. {
  268. CreateModuleInfoApple(pModuleInfoAppleArray, arrayCapacity, requiredArraySize, arraySize,
  269. pTypeFilter, modulePath, currentSegmentPos, pMachHeader, 0); // offset is 0 because dyld is already loaded
  270. }
  271. // Use this to compare results
  272. // printf("vmmap -w %lld", (int64_t)pid);
  273. }
  274. return requiredArraySize;
  275. }
  276. #endif // EATHREAD_APPLE_GETMODULEINFO_ENABLED
  277. ///////////////////////////////////////////////////////////////////////////////
  278. // GetInstructionPointer
  279. //
  280. EATHREADLIB_API void GetInstructionPointer(void*& pInstruction)
  281. {
  282. pInstruction = __builtin_return_address(0); // Works for all Apple platforms and compilers (gcc and clang).
  283. }
  284. ///////////////////////////////////////////////////////////////////////////////
  285. // InitCallstack
  286. //
  287. EATHREADLIB_API void InitCallstack()
  288. {
  289. EA::Thread::Allocator* pAllocator = EA::Thread::GetAllocator();
  290. EAT_ASSERT_MSG(pAllocator != NULL, "EA::Thread::SetAllocator needs to be called on app startup.");
  291. if(pAllocator)
  292. gCallstackFutex = new(pAllocator->Alloc(sizeof(Futex))) Futex;
  293. }
  294. ///////////////////////////////////////////////////////////////////////////////
  295. // ShutdownCallstack
  296. //
  297. EATHREADLIB_API void ShutdownCallstack()
  298. {
  299. EA::Thread::Allocator* pAllocator = EA::Thread::GetAllocator();
  300. EAT_ASSERT_MSG(pAllocator != NULL, "EAThread requires an allocator to be available between InitCallstack and ShutdownCallstack.");
  301. if(pAllocator)
  302. {
  303. if(gModuleInfoAppleArray)
  304. ReallocModuleInfoApple(0);
  305. if(gCallstackFutex)
  306. {
  307. pAllocator->Free(gCallstackFutex);
  308. gCallstackFutex = NULL;
  309. }
  310. }
  311. }
  312. ///////////////////////////////////////////////////////////////////////////////
  313. // GetCallstack
  314. //
  315. // Capture up to nReturnAddressArrayCapacity elements of the call stack,
  316. // or the whole callstack, whichever is smaller.
  317. //
  318. // ARM
  319. // Apple defines a different ABI than the ARM eabi used by Linux and the ABI used
  320. // by Microsoft. It implements a predictable stack frame system using r7 as the
  321. // frame pointer. Documentation:
  322. // http://developer.apple.com/library/ios/#documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html
  323. //
  324. // Basically, Apple uses r7 as a frame pointer. So for any function you are
  325. // executing, r7 + 4 is the LR passed to us by the caller and is the PC of
  326. // the parent. And r7 + 0 is a pointer to the parent's r7.
  327. // x86/x64
  328. // The ABI is similar except using the different registers from the different CPU.
  329. //
  330. EATHREADLIB_API size_t GetCallstack(void* pReturnAddressArray[], size_t nReturnAddressArrayCapacity, const CallstackContext* pContext)
  331. {
  332. #if defined(EA_DEBUG)
  333. memset(pReturnAddressArray, 0, nReturnAddressArrayCapacity * sizeof(void*));
  334. #endif
  335. #if defined(EA_PROCESSOR_ARM) || defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)
  336. struct StackFrame {
  337. StackFrame* mpParentStackFrame;
  338. void* mpReturnPC;
  339. };
  340. StackFrame* pStackFrame;
  341. void* pInstruction;
  342. size_t index = 0;
  343. if(pContext)
  344. {
  345. #if defined(EA_PROCESSOR_ARM32)
  346. pStackFrame = (StackFrame*)pContext->mFP;
  347. pInstruction = (void*) pContext->mPC;
  348. #define FrameIsAligned(pStackFrame) ((((uintptr_t)pStackFrame) & 0x1) == 0)
  349. #elif defined(EA_PROCESSOR_ARM64)
  350. pStackFrame = (StackFrame*)pContext->mFP;
  351. pInstruction = (void*) pContext->mPC;
  352. #define FrameIsAligned(pStackFrame) ((((uintptr_t)pStackFrame) & 0xf) == 0)
  353. #elif defined(EA_PROCESSOR_X86_64)
  354. pStackFrame = (StackFrame*)pContext->mRBP;
  355. pInstruction = (void*) pContext->mRIP;
  356. #define FrameIsAligned(pStackFrame) ((((uintptr_t)pStackFrame) & 0xf) == 0)
  357. #elif defined(EA_PROCESSOR_X86)
  358. pStackFrame = (StackFrame*)pContext->mEBP;
  359. pInstruction = (void*) pContext->mEIP;
  360. #define FrameIsAligned(pStackFrame) ((((uintptr_t)pStackFrame) & 0xf) == 8)
  361. #endif
  362. // Write the instruction to pReturnAddressArray. In this case we have this thread
  363. // reading the callstack from another thread.
  364. if(index < nReturnAddressArrayCapacity)
  365. pReturnAddressArray[index++] = pInstruction;
  366. }
  367. else // Else get the current values...
  368. {
  369. pStackFrame = (StackFrame*)__builtin_frame_address(0);
  370. GetInstructionPointer(pInstruction); // Intentionally don't call EAGetInstructionPointer, because it won't set the Thumb bit if this is Thumb code.
  371. // Don't write pInstruction to pReturnAddressArray, as pInstruction refers to the code in *this* function, whereas we want to start with caller's call frame.
  372. }
  373. // We can do some range validation if we have a pthread id.
  374. StackFrame* pStackBase;
  375. StackFrame* pStackLimit;
  376. const bool bThreadIsCurrent = (pContext == NULL); // To do: allow this to also tell if the thread is current for the case that pContext is non-NULL. We can do that by reading the current frame address and walking it backwards a few times and seeing if any value matches pStackFrame.
  377. if(bThreadIsCurrent)
  378. {
  379. pthread_t pthread = pthread_self(); // This makes the assumption that the current thread is a pthread and not just a kernel thread.
  380. pStackBase = reinterpret_cast<StackFrame*>(pthread_get_stackaddr_np(pthread));
  381. pStackLimit = pStackBase - (pthread_get_stacksize_np(pthread) / sizeof(StackFrame));
  382. }
  383. else
  384. { // Make a conservative guess.
  385. pStackBase = pStackFrame + ((1024 * 1024) / sizeof(StackFrame));
  386. pStackLimit = pStackFrame - ((1024 * 1024) / sizeof(StackFrame));
  387. }
  388. // To consider: Do some validation of the PC. We can validate it by making sure it's with 20 MB
  389. // of our PC and also verify that the instruction before it (be it Thumb or ARM) is a BL or BLX
  390. // function call instruction (in the case of EA_PROCESSOR_ARM).
  391. // To consider: Verify that each successive pStackFrame is at a higher address than the last,
  392. // as otherwise the data must be corrupt.
  393. if((index < nReturnAddressArrayCapacity) && pStackFrame && FrameIsAligned(pStackFrame))
  394. {
  395. pReturnAddressArray[index++] = pStackFrame->mpReturnPC; // Should happen to be equal to pContext->mLR.
  396. while(pStackFrame && pStackFrame->mpReturnPC && (index < nReturnAddressArrayCapacity))
  397. {
  398. pStackFrame = pStackFrame->mpParentStackFrame;
  399. if(pStackFrame && FrameIsAligned(pStackFrame) && pStackFrame->mpReturnPC && (pStackFrame < pStackBase) && (pStackFrame > pStackLimit))
  400. pReturnAddressArray[index++] = pStackFrame->mpReturnPC;
  401. else
  402. break;
  403. }
  404. }
  405. return index;
  406. #elif EACALLSTACK_GLIBC_BACKTRACE_AVAILABLE // Mac OS X with GlibC
  407. // One way to get the callstack of another thread, via signal handling:
  408. // https://github.com/albertz/openlierox/blob/0.59/src/common/Debug_GetCallstack.cpp
  409. size_t count = 0;
  410. // The pContext option is not currently supported.
  411. if(pContext == NULL) // To do: || pContext refers to this thread.
  412. {
  413. count = (size_t)backtrace(pReturnAddressArray, (int)nReturnAddressArrayCapacity);
  414. if(count > 0)
  415. {
  416. --count; // Remove the first entry, because it refers to this function and by design we don't include this function.
  417. memmove(pReturnAddressArray, pReturnAddressArray + 1, count * sizeof(void*));
  418. }
  419. }
  420. // else fall through to code that manually reads stack frames?
  421. return count;
  422. #else
  423. EA_UNUSED(pReturnAddressArray);
  424. EA_UNUSED(nReturnAddressArrayCapacity);
  425. EA_UNUSED(pContext);
  426. return 0;
  427. #endif
  428. }
  429. ///////////////////////////////////////////////////////////////////////////////
  430. // GetCallstackContext
  431. //
  432. // Convert a full Context to a CallstackContext (subset of context).
  433. //
  434. EATHREADLIB_API void GetCallstackContext(CallstackContext& context, const Context* pContext)
  435. {
  436. #if defined(EA_PROCESSOR_X86_64)
  437. context.mRIP = pContext->Rip;
  438. context.mRSP = pContext->Rsp;
  439. context.mRBP = pContext->Rbp;
  440. #elif defined(EA_PROCESSOR_X86)
  441. context.mEIP = pContext->Eip;
  442. context.mESP = pContext->Esp;
  443. context.mEBP = pContext->Ebp;
  444. #elif defined(EA_PROCESSOR_ARM32)
  445. context.mFP = pContext->mGpr[7]; // Apple uses R7 for the frame pointer in both ARM and Thumb CPU modes.
  446. context.mSP = pContext->mGpr[13];
  447. context.mLR = pContext->mGpr[14];
  448. context.mPC = pContext->mGpr[15];
  449. #elif defined(EA_PROCESSOR_ARM64)
  450. context.mFP = pContext->mGpr[29];
  451. context.mSP = pContext->mGpr[31];
  452. context.mLR = pContext->mGpr[30];
  453. context.mPC = pContext->mPC;
  454. #else
  455. EAT_FAIL_MSG("Platform unsupported");
  456. #endif
  457. }
  458. ///////////////////////////////////////////////////////////////////////////////
  459. // GetModuleFromAddress
  460. //
  461. // Returns the required strlen of pModuleName.
  462. //
  463. EATHREADLIB_API size_t GetModuleFromAddress(const void* pCodeAddress, char* pModuleName, size_t moduleNameCapacity)
  464. {
  465. if(moduleNameCapacity > 0)
  466. pModuleName[0] = 0;
  467. #if EATHREAD_APPLE_GETMODULEINFO_ENABLED
  468. Dl_info dlInfo; memset(&dlInfo, 0, sizeof(dlInfo)); // Just memset because dladdr sometimes leaves dli_fname untouched.
  469. int result = dladdr(pCodeAddress, &dlInfo);
  470. if((result != 0) && dlInfo.dli_fname) // It seems that usually this fails.
  471. return strlcpy(pModuleName, dlInfo.dli_fname, moduleNameCapacity);
  472. // To do: Make this be dynamically resized as needed.
  473. const size_t kCapacity = 64;
  474. ModuleInfoApple moduleInfoAppleArray[kCapacity];
  475. size_t requiredCapacity = GetModuleInfoApple(moduleInfoAppleArray, kCapacity, "__TEXT", true); // To consider: Make this true (use cache) configurable.
  476. uint64_t codeAddress = (uint64_t)(uintptr_t)pCodeAddress;
  477. if(requiredCapacity > kCapacity)
  478. requiredCapacity = kCapacity;
  479. for(size_t i = 0; i < requiredCapacity; i++)
  480. {
  481. const ModuleInfoApple& miaUser = moduleInfoAppleArray[i];
  482. if((miaUser.mBaseAddress < codeAddress) && (codeAddress < (miaUser.mBaseAddress + miaUser.mSize)))
  483. return strlcpy(pModuleName, miaUser.mPath, moduleNameCapacity);
  484. }
  485. #endif
  486. return 0;
  487. }
  488. ///////////////////////////////////////////////////////////////////////////////
  489. // GetModuleHandleFromAddress
  490. //
  491. EATHREADLIB_API ModuleHandle GetModuleHandleFromAddress(const void* pCodeAddress)
  492. {
  493. #if EATHREAD_APPLE_GETMODULEINFO_ENABLED
  494. Dl_info dlInfo; memset(&dlInfo, 0, sizeof(dlInfo)); // Just memset because dladdr sometimes leaves fields untouched.
  495. int result = dladdr(pCodeAddress, &dlInfo);
  496. if(result != 0)
  497. return dlInfo.dli_fbase; // Is the object load base the same as the module handle?
  498. // Try using GetModuleInfoApple to get the information.
  499. // To do: Make this be dynamically resized as needed.
  500. const size_t kCapacity = 256;
  501. ModuleInfoApple moduleInfoAppleArray[kCapacity];
  502. size_t requiredCapacity = GetModuleInfoApple(moduleInfoAppleArray, kCapacity, "__TEXT", true); // To consider: Make this true (use cache) configurable.
  503. uint64_t codeAddress = (uint64_t)(uintptr_t)pCodeAddress;
  504. if(requiredCapacity > kCapacity)
  505. requiredCapacity = kCapacity;
  506. for(size_t i = 0; i < requiredCapacity; i++)
  507. {
  508. ModuleInfoApple& miaUser = moduleInfoAppleArray[i];
  509. if((miaUser.mBaseAddress < codeAddress) && (codeAddress < (miaUser.mBaseAddress + miaUser.mSize)))
  510. return (ModuleHandle)miaUser.mBaseAddress;
  511. }
  512. #endif
  513. return 0;
  514. }
  515. ///////////////////////////////////////////////////////////////////////////////
  516. // GetCallstackContext
  517. //
  518. EATHREADLIB_API bool GetCallstackContext(CallstackContext& context, intptr_t threadId)
  519. {
  520. // For Apple pthread_t is typedef'd to an internally defined _opaque_pthread_t*.
  521. bool threadIsSelf = (threadId == (intptr_t)EA::Thread::kThreadIdInvalid) || // Due to a specification mistake, this function
  522. (threadId == (intptr_t)EA::Thread::kThreadIdCurrent) || // accepts kThreadInvalid to mean current.
  523. (threadId == (intptr_t)pthread_self());
  524. if(threadIsSelf)
  525. {
  526. bool result = true;
  527. context.mStackBase = (uintptr_t)GetStackBase();
  528. context.mStackLimit = (uintptr_t)GetStackLimit();
  529. #if defined(EA_PROCESSOR_ARM32)
  530. void* p;
  531. EAGetInstructionPointer(p);
  532. context.mPC = (uint32_t)p;
  533. context.mFP = (uint32_t)__builtin_frame_address(0); // This data isn't exactly right. We want to return the registers as they
  534. context.mSP = (uint32_t)__builtin_frame_address(0); // are for the caller, not for us. Without doing that we end up reporting
  535. context.mLR = (uint32_t)__builtin_return_address(0); // an extra frame (this one) on the top of callstacks.
  536. #elif defined(EA_PROCESSOR_ARM64)
  537. void* p;
  538. EAGetInstructionPointer(p);
  539. context.mPC = (uint64_t)p;
  540. context.mFP = (uint64_t)__builtin_frame_address(0);
  541. context.mSP = (uint64_t)__builtin_frame_address(0);
  542. context.mLR = (uint64_t)__builtin_return_address(0);
  543. #elif defined(EA_PROCESSOR_X86_64)
  544. context.mRIP = (uint64_t)__builtin_return_address(0);
  545. context.mRSP = 0;
  546. context.mRBP = (uint64_t)__builtin_frame_address(1);
  547. #elif defined(EA_PROCESSOR_X86)
  548. context.mEIP = (uint32_t)__builtin_return_address(0);
  549. context.mESP = 0;
  550. context.mEBP = (uint32_t)__builtin_frame_address(1);
  551. #else
  552. // platform not supported
  553. result = false;
  554. #endif
  555. return result;
  556. }
  557. else
  558. {
  559. // Pause the thread, get its state, unpause it.
  560. //
  561. // Question: Is it truly necessary to suspend a thread in Apple platforms in order to read
  562. // their state? It is usually so for other platforms doing the same kind of thing.
  563. //
  564. // Question: Is it dangerous to suspend an arbitrary thread? Often such a thing is dangerous
  565. // because that other thread might for example have some kernel mutex locked that we need.
  566. // We'll have to see, as it's a great benefit for us to be able to read callstack contexts.
  567. // Another solution would be to inject a signal handler into the thread and signal it and
  568. // have the handler read context information, if that can be useful. There's example code
  569. // on the Internet for that.
  570. // Some documentation:
  571. // http://www.linuxselfhelp.com/gnu/machinfo/html_chapter/mach_7.html
  572. mach_port_t thread = pthread_mach_thread_np((pthread_t)threadId); // Convert pthread_t to kernel thread id.
  573. kern_return_t result = thread_suspend(thread);
  574. if(result == KERN_SUCCESS)
  575. {
  576. #if defined(EA_PROCESSOR_ARM32)
  577. arm_thread_state_t threadState; memset(&threadState, 0, sizeof(threadState));
  578. mach_msg_type_number_t stateCount = MACHINE_THREAD_STATE_COUNT;
  579. result = thread_get_state(thread, MACHINE_THREAD_STATE, (natural_t*)(uintptr_t)&threadState, &stateCount);
  580. context.mFP = threadState.__r[7]; // Apple uses R7 for the frame pointer in both ARM and Thumb CPU modes.
  581. context.mPC = threadState.__pc;
  582. context.mSP = threadState.__sp;
  583. context.mLR = threadState.__lr;
  584. #elif defined(EA_PROCESSOR_ARM64)
  585. __darwin_arm_thread_state64 threadState; memset(&threadState, 0, sizeof(threadState));
  586. mach_msg_type_number_t stateCount = MACHINE_THREAD_STATE_COUNT;
  587. result = thread_get_state(thread, MACHINE_THREAD_STATE, (natural_t*)(uintptr_t)&threadState, &stateCount);
  588. context.mFP = threadState.__fp;
  589. context.mPC = threadState.__pc;
  590. context.mSP = threadState.__sp;
  591. context.mLR = threadState.__lr;
  592. #elif defined(EA_PROCESSOR_X86_64)
  593. // Note: This is yielding gibberish data for me, despite everything seemingly being done correctly.
  594. x86_thread_state_t threadState; memset(&threadState, 0, sizeof(threadState));
  595. mach_msg_type_number_t stateCount = MACHINE_THREAD_STATE_COUNT;
  596. result = thread_get_state(thread, MACHINE_THREAD_STATE, (natural_t*)(uintptr_t)&threadState, &stateCount);
  597. context.mRIP = threadState.uts.ts64.__rip;
  598. context.mRSP = threadState.uts.ts64.__rsp;
  599. context.mRBP = threadState.uts.ts64.__rbp;
  600. #elif defined(EA_PROCESSOR_X86)
  601. // Note: This is yielding gibberish data for me, despite everything seemingly being done correctly.
  602. x86_thread_state_t threadState; memset(&threadState, 0, sizeof(threadState));
  603. mach_msg_type_number_t stateCount = MACHINE_THREAD_STATE_COUNT;
  604. result = thread_get_state(thread, MACHINE_THREAD_STATE, (natural_t*)(uintptr_t)&threadState, &stateCount);
  605. context.mEIP = threadState.uts.ts32.__eip;
  606. context.mESP = threadState.uts.ts32.__esp;
  607. context.mEBP = threadState.uts.ts32.__ebp;
  608. #endif
  609. thread_resume(thread);
  610. return (result == KERN_SUCCESS);
  611. }
  612. }
  613. // Not currently implemented for the given platform.
  614. memset(&context, 0, sizeof(context));
  615. return false;
  616. }
  617. ///////////////////////////////////////////////////////////////////////////////
  618. // GetCallstackContextSysThreadId
  619. //
  620. EATHREADLIB_API bool GetCallstackContextSysThreadId(CallstackContext& context, intptr_t sysThreadId)
  621. {
  622. pthread_t pthread = pthread_from_mach_thread_np((mach_port_t)sysThreadId);
  623. return GetCallstackContext(context, (intptr_t)pthread);
  624. }
  625. // To do: Remove the usage of sStackBase for the platforms that it's not needed,
  626. // as can be seen from the logic below. For example Mac OSX probably doesn't need it.
  627. static EA::Thread::ThreadLocalStorage sStackBase;
  628. ///////////////////////////////////////////////////////////////////////////////
  629. // SetStackBase
  630. //
  631. EATHREADLIB_API void SetStackBase(void* pStackBase)
  632. {
  633. if(pStackBase)
  634. sStackBase.SetValue(pStackBase);
  635. else
  636. {
  637. pStackBase = __builtin_frame_address(0);
  638. if(pStackBase)
  639. SetStackBase(pStackBase);
  640. // Else failure; do nothing.
  641. }
  642. }
  643. ///////////////////////////////////////////////////////////////////////////////
  644. // GetStackBase
  645. //
  646. EATHREADLIB_API void* GetStackBase()
  647. {
  648. #if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_APPLE)
  649. void* pBase;
  650. if(GetPthreadStackInfo(&pBase, NULL))
  651. return pBase;
  652. #endif
  653. // Else we require the user to have set this previously, usually via a call
  654. // to SetStackBase() in the start function of this currently executing
  655. // thread (or main for the main thread).
  656. return sStackBase.GetValue();
  657. }
  658. ///////////////////////////////////////////////////////////////////////////////
  659. // GetStackLimit
  660. //
  661. EATHREADLIB_API void* GetStackLimit()
  662. {
  663. #if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_APPLE)
  664. void* pLimit;
  665. if(GetPthreadStackInfo(NULL, &pLimit))
  666. return pLimit;
  667. #endif
  668. // If this fails then we might have an issue where you are using GCC but not
  669. // using the GCC standard library glibc. Or maybe glibc doesn't support
  670. // __builtin_frame_address on this platform. Or maybe you aren't using GCC but
  671. // rather a compiler that masquerades as GCC (common situation).
  672. void* pStack = __builtin_frame_address(0);
  673. return (void*)((uintptr_t)pStack & ~4095); // Round down to nearest page.
  674. }
  675. } // namespace Thread
  676. } // namespace EA