StackTrace.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. #include "il2cpp-config.h"
  2. #include "StackTrace.h"
  3. #include "il2cpp-object-internals.h"
  4. #include "os/Event.h"
  5. #include "os/StackTrace.h"
  6. #include "os/Thread.h"
  7. #include "os/ThreadLocalValue.h"
  8. #include "os/Image.h"
  9. #include "vm/Method.h"
  10. #include "vm/Thread.h"
  11. #include "vm/Type.h"
  12. #include "vm-utils/Debugger.h"
  13. #include "vm-utils/NativeSymbol.h"
  14. #include "vm-utils/DebugSymbolReader.h"
  15. #include "vm-utils/Debugger.h"
  16. #include <map>
  17. #include <cstdio>
  18. namespace il2cpp
  19. {
  20. namespace vm
  21. {
  22. #if IL2CPP_ENABLE_STACKTRACES
  23. class CachedInfo
  24. {
  25. int32_t m_depth;
  26. const void* m_stackPointer;
  27. public:
  28. CachedInfo() : m_depth(INT_MAX), m_stackPointer(NULL) {}
  29. void Update(int32_t depth, const void *stackPointer)
  30. {
  31. m_depth = depth;
  32. m_stackPointer = stackPointer;
  33. }
  34. bool CheckCondition(int32_t depth, const void *stackPointer) const
  35. {
  36. // We can use cached value if stack pointer is the same and not NULL, and 'depth' has been incremented since previous call
  37. return m_stackPointer != NULL && stackPointer == m_stackPointer && depth - 1 == m_depth;
  38. }
  39. };
  40. class MethodStack
  41. {
  42. protected:
  43. os::ThreadLocalValue s_StackFrames;
  44. os::ThreadLocalValue s_StoredCachedInfo;
  45. inline StackFrames* GetStackFramesRaw()
  46. {
  47. StackFrames* stackFrames = NULL;
  48. os::ErrorCode result = s_StackFrames.GetValue(reinterpret_cast<void**>(&stackFrames));
  49. Assert(result == os::kErrorCodeSuccess);
  50. return stackFrames;
  51. }
  52. inline CachedInfo* GetStoredCachedInfoRaw()
  53. {
  54. CachedInfo* storedCachedInfo = NULL;
  55. os::ErrorCode result = s_StoredCachedInfo.GetValue(reinterpret_cast<void**>(&storedCachedInfo));
  56. Assert(result == os::kErrorCodeSuccess);
  57. return storedCachedInfo;
  58. }
  59. public:
  60. inline void InitializeForCurrentThread()
  61. {
  62. if (GetStackFramesRaw() != NULL)
  63. return;
  64. StackFrames* stackFrames = new StackFrames();
  65. stackFrames->reserve(64);
  66. os::ErrorCode result = s_StackFrames.SetValue(stackFrames);
  67. Assert(result == os::kErrorCodeSuccess);
  68. CachedInfo* cachedInfo = new CachedInfo();
  69. result = s_StoredCachedInfo.SetValue(cachedInfo);
  70. Assert(result == os::kErrorCodeSuccess);
  71. }
  72. inline void CleanupForCurrentThread()
  73. {
  74. StackFrames* frames = GetStackFramesRaw();
  75. if (frames == NULL)
  76. return;
  77. delete frames;
  78. CachedInfo* cachedInfo = GetStoredCachedInfoRaw();
  79. if (cachedInfo == NULL)
  80. return;
  81. delete cachedInfo;
  82. os::ErrorCode result = s_StackFrames.SetValue(NULL);
  83. Assert(result == os::kErrorCodeSuccess);
  84. result = s_StoredCachedInfo.SetValue(NULL);
  85. Assert(result == os::kErrorCodeSuccess);
  86. }
  87. };
  88. #if IL2CPP_ENABLE_STACKTRACE_SENTRIES
  89. class StacktraceSentryMethodStack : public MethodStack
  90. {
  91. public:
  92. inline const StackFrames* GetStackFrames()
  93. {
  94. return GetStackFramesRaw();
  95. }
  96. inline const StackFrames* GetCachedStackFrames(int32_t depth, const void* stackPointer)
  97. {
  98. return GetStackFrames();
  99. }
  100. inline bool GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
  101. {
  102. const StackFrames& frames = *GetStackFramesRaw();
  103. if (static_cast<int>(frames.size()) + depth < 1)
  104. return false;
  105. frame = frames[frames.size() - 1 + depth];
  106. return true;
  107. }
  108. inline void PushFrame(Il2CppStackFrameInfo& frame)
  109. {
  110. GetStackFramesRaw()->push_back(frame);
  111. }
  112. inline void PopFrame()
  113. {
  114. StackFrames* stackFrames = GetStackFramesRaw();
  115. stackFrames->pop_back();
  116. }
  117. inline const void* GetStackPointer()
  118. {
  119. return nullptr;
  120. }
  121. };
  122. #endif // IL2CPP_ENABLE_STACKTRACE_SENTRIES
  123. #if IL2CPP_ENABLE_NATIVE_STACKTRACES
  124. #if IL2CPP_MONO_DEBUGGER
  125. class DebuggerMethodStack : public MethodStack
  126. {
  127. public:
  128. inline const StackFrames* GetStackFrames()
  129. {
  130. StackFrames* stackFrames = GetStackFramesRaw();
  131. if (stackFrames == NULL)
  132. return stackFrames;
  133. stackFrames->clear();
  134. utils::Debugger::GetStackFrames(stackFrames);
  135. return stackFrames;
  136. }
  137. inline const StackFrames* GetCachedStackFrames(int32_t depth, const void* stackPointer)
  138. {
  139. CachedInfo* cachedInfo = GetStoredCachedInfoRaw();
  140. const StackFrames* stackFrames = cachedInfo->CheckCondition(depth, stackPointer) ? GetStackFramesRaw() : GetStackFrames();
  141. cachedInfo->Update(depth, stackPointer);
  142. return stackFrames;
  143. }
  144. inline bool GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
  145. {
  146. const StackFrames& frames = *GetStackFrames();
  147. if (static_cast<int>(frames.size()) + depth < 1)
  148. return false;
  149. frame = frames[frames.size() - 1 + depth];
  150. return true;
  151. }
  152. inline void PushFrame(Il2CppStackFrameInfo& frame)
  153. {
  154. }
  155. inline void PopFrame()
  156. {
  157. }
  158. inline const void* GetStackPointer()
  159. {
  160. return nullptr;
  161. }
  162. };
  163. #else
  164. class NativeMethodStack : public MethodStack
  165. {
  166. static bool GetStackFramesCallback(Il2CppMethodPointer frame, void* context)
  167. {
  168. const MethodInfo* method = il2cpp::utils::NativeSymbol::GetMethodFromNativeSymbol(frame);
  169. StackFrames* stackFrames = static_cast<StackFrames*>(context);
  170. if (method != NULL)
  171. {
  172. bool frames_added = il2cpp::utils::DebugSymbolReader::AddStackFrames(reinterpret_cast<void*>(frame), stackFrames);
  173. if (!frames_added)
  174. {
  175. Il2CppStackFrameInfo frameInfo = { 0 };
  176. frameInfo.method = method;
  177. frameInfo.raw_ip = reinterpret_cast<uintptr_t>(frame) - reinterpret_cast<uintptr_t>(os::Image::GetImageBase());
  178. stackFrames->push_back(frameInfo);
  179. }
  180. }
  181. return true;
  182. }
  183. struct GetStackFrameAtContext
  184. {
  185. int32_t currentDepth;
  186. const MethodInfo* method;
  187. };
  188. static bool GetStackFrameAtCallback(Il2CppMethodPointer frame, void* context)
  189. {
  190. const MethodInfo* method = il2cpp::utils::NativeSymbol::GetMethodFromNativeSymbol(frame);
  191. GetStackFrameAtContext* ctx = static_cast<GetStackFrameAtContext*>(context);
  192. if (method != NULL)
  193. {
  194. if (ctx->currentDepth == 0)
  195. {
  196. ctx->method = method;
  197. return false;
  198. }
  199. ctx->currentDepth++;
  200. }
  201. return true;
  202. }
  203. public:
  204. inline const StackFrames* GetStackFrames()
  205. {
  206. StackFrames* stackFrames = GetStackFramesRaw();
  207. if (stackFrames == NULL)
  208. return stackFrames;
  209. stackFrames->clear();
  210. os::StackTrace::WalkStack(&NativeMethodStack::GetStackFramesCallback, stackFrames, os::StackTrace::kFirstCalledToLastCalled);
  211. return stackFrames;
  212. }
  213. // Avoiding calling GetStackFrames() method for the same stack trace with incremented 'depth' value
  214. inline const StackFrames* GetCachedStackFrames(int32_t depth, const void* stackPointer)
  215. {
  216. CachedInfo* cachedInfo = GetStoredCachedInfoRaw();
  217. const StackFrames* stackFrames = cachedInfo->CheckCondition(depth, stackPointer) ? GetStackFramesRaw() : GetStackFrames();
  218. cachedInfo->Update(depth, stackPointer);
  219. return stackFrames;
  220. }
  221. inline bool GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
  222. {
  223. GetStackFrameAtContext context = { depth, NULL };
  224. os::StackTrace::WalkStack(&NativeMethodStack::GetStackFrameAtCallback, &context, os::StackTrace::kLastCalledToFirstCalled);
  225. if (context.method != NULL)
  226. {
  227. frame.method = context.method;
  228. return true;
  229. }
  230. return false;
  231. }
  232. inline void PushFrame(Il2CppStackFrameInfo& frame)
  233. {
  234. }
  235. inline void PopFrame()
  236. {
  237. }
  238. // Returns SP value or nullptr if not implemented
  239. inline const void* GetStackPointer()
  240. {
  241. return os::StackTrace::GetStackPointer();
  242. }
  243. };
  244. #endif // IL2CPP_MONO_DEBUGGER
  245. #endif // IL2CPP_ENABLE_NATIVE_STACKTRACES
  246. #else
  247. static StackFrames s_EmptyStack;
  248. class NoOpMethodStack
  249. {
  250. public:
  251. inline void InitializeForCurrentThread()
  252. {
  253. }
  254. inline void CleanupForCurrentThread()
  255. {
  256. }
  257. inline const StackFrames* GetStackFrames()
  258. {
  259. return &s_EmptyStack;
  260. }
  261. inline const StackFrames* GetCachedStackFrames(int32_t depth, const void* stackPointer)
  262. {
  263. return GetStackFrames();
  264. }
  265. inline bool GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
  266. {
  267. return false;
  268. }
  269. inline void PushFrame(Il2CppStackFrameInfo& frame)
  270. {
  271. }
  272. inline void PopFrame()
  273. {
  274. }
  275. inline const void* GetStackPointer()
  276. {
  277. return nullptr;
  278. }
  279. };
  280. #endif // IL2CPP_ENABLE_STACKTRACES
  281. #if IL2CPP_ENABLE_STACKTRACES
  282. #if IL2CPP_ENABLE_STACKTRACE_SENTRIES
  283. StacktraceSentryMethodStack s_MethodStack;
  284. #elif IL2CPP_ENABLE_NATIVE_STACKTRACES
  285. #if IL2CPP_MONO_DEBUGGER
  286. DebuggerMethodStack s_MethodStack;
  287. #else
  288. NativeMethodStack s_MethodStack;
  289. #endif
  290. #endif
  291. #else
  292. NoOpMethodStack s_MethodStack;
  293. #endif // IL2CPP_ENABLE_STACKTRACES
  294. // Current thread functions
  295. void StackTrace::InitializeStackTracesForCurrentThread()
  296. {
  297. s_MethodStack.InitializeForCurrentThread();
  298. }
  299. void StackTrace::CleanupStackTracesForCurrentThread()
  300. {
  301. s_MethodStack.CleanupForCurrentThread();
  302. }
  303. const StackFrames* StackTrace::GetStackFrames()
  304. {
  305. return s_MethodStack.GetStackFrames();
  306. }
  307. const StackFrames* StackTrace::GetCachedStackFrames(int32_t depth)
  308. {
  309. return s_MethodStack.GetCachedStackFrames(depth, GetStackPointer());
  310. }
  311. bool StackTrace::GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
  312. {
  313. Assert(depth <= 0 && "Frame depth must be 0 or less");
  314. return s_MethodStack.GetStackFrameAt(depth, frame);
  315. }
  316. void StackTrace::WalkFrameStack(Il2CppFrameWalkFunc callback, void* context)
  317. {
  318. const StackFrames& frames = *GetStackFrames();
  319. for (StackFrames::const_iterator it = frames.begin(); it != frames.end(); it++)
  320. callback(&*it, context);
  321. }
  322. #if IL2CPP_TINY_DEBUGGER
  323. static std::map<const MethodInfo*, std::string> s_MethodNames;
  324. static std::string MethodNameFor(const MethodInfo* method)
  325. {
  326. auto cachedMethodNameEntry = s_MethodNames.find(method);
  327. if (cachedMethodNameEntry != s_MethodNames.end())
  328. return cachedMethodNameEntry->second;
  329. std::string methodName;
  330. methodName += vm::Method::GetFullName(method);
  331. methodName += " (";
  332. uint32_t numberOfParameters = vm::Method::GetParamCount(method);
  333. for (uint32_t j = 0; j < numberOfParameters; ++j)
  334. {
  335. const Il2CppType* parameterType = vm::Method::GetParam(method, j);
  336. methodName += vm::Type::GetName(parameterType, IL2CPP_TYPE_NAME_FORMAT_FULL_NAME);
  337. if (j != numberOfParameters - 1)
  338. methodName += ", ";
  339. }
  340. methodName += ")";
  341. s_MethodNames[method] = methodName;
  342. return methodName;
  343. }
  344. const int s_StackTraceSize = 4096;
  345. static char s_StackTrace[s_StackTraceSize];
  346. static int s_StackTraceOffset = 0;
  347. static void AppendToStackTrace(const char* value)
  348. {
  349. if (s_StackTraceOffset < s_StackTraceSize)
  350. s_StackTraceOffset += snprintf(s_StackTrace + s_StackTraceOffset, s_StackTraceSize - s_StackTraceOffset, "%s", value);
  351. }
  352. const char* StackTrace::GetStackTrace()
  353. {
  354. // Since a pointer to a static buffer is used to store the stack trace, only
  355. // once thread should use it. Tiny does not support managed code on non-main
  356. // threads, so there is no need to use a thread local buffer here. Protect this
  357. // from access on multiple threads by not returning anyting on non-main threads.
  358. if (vm::Thread::Current() != vm::Thread::Main())
  359. return NULL;
  360. const StackFrames* frames = s_MethodStack.GetStackFrames();
  361. const size_t numberOfFramesToSkip = 1;
  362. int startFrame = (int)frames->size() - 1 - numberOfFramesToSkip;
  363. s_StackTraceOffset = 0;
  364. for (int i = startFrame; i > 0; i--)
  365. {
  366. if (i == startFrame)
  367. AppendToStackTrace("at ");
  368. else
  369. AppendToStackTrace(" at ");
  370. Il2CppStackFrameInfo stackFrame = (*frames)[i];
  371. AppendToStackTrace(MethodNameFor(stackFrame.method).c_str());
  372. if (stackFrame.filePath != NULL)
  373. {
  374. AppendToStackTrace(" in ");
  375. AppendToStackTrace(stackFrame.filePath);
  376. AppendToStackTrace(":");
  377. AppendToStackTrace(std::to_string(stackFrame.sourceCodeLineNumber).c_str());
  378. }
  379. if (i != 1)
  380. AppendToStackTrace("\n");
  381. }
  382. return s_StackTrace;
  383. }
  384. #endif
  385. void StackTrace::PushFrame(Il2CppStackFrameInfo& frame)
  386. {
  387. s_MethodStack.PushFrame(frame);
  388. }
  389. void StackTrace::PopFrame()
  390. {
  391. s_MethodStack.PopFrame();
  392. }
  393. const void* StackTrace::GetStackPointer()
  394. {
  395. return s_MethodStack.GetStackPointer();
  396. }
  397. // Remote thread functions
  398. struct GetThreadFrameAtContext
  399. {
  400. il2cpp::os::Event apcDoneEvent;
  401. int32_t depth;
  402. Il2CppStackFrameInfo* frame;
  403. bool hasResult;
  404. };
  405. struct WalkThreadFrameStackContext
  406. {
  407. il2cpp::os::Event apcDoneEvent;
  408. Il2CppFrameWalkFunc callback;
  409. void* userContext;
  410. };
  411. struct GetThreadStackDepthContext
  412. {
  413. il2cpp::os::Event apcDoneEvent;
  414. int32_t stackDepth;
  415. };
  416. struct GetThreadTopFrameContext
  417. {
  418. il2cpp::os::Event apcDoneEvent;
  419. Il2CppStackFrameInfo* frame;
  420. bool hasResult;
  421. };
  422. static void STDCALL GetThreadFrameAtCallback(void* context)
  423. {
  424. GetThreadFrameAtContext* ctx = static_cast<GetThreadFrameAtContext*>(context);
  425. ctx->hasResult = StackTrace::GetStackFrameAt(ctx->depth, *ctx->frame);
  426. ctx->apcDoneEvent.Set();
  427. }
  428. bool StackTrace::GetThreadStackFrameAt(Il2CppThread* thread, int32_t depth, Il2CppStackFrameInfo& frame)
  429. {
  430. #if IL2CPP_ENABLE_STACKTRACES
  431. GetThreadFrameAtContext apcContext;
  432. apcContext.depth = depth;
  433. apcContext.frame = &frame;
  434. thread->GetInternalThread()->handle->QueueUserAPC(GetThreadFrameAtCallback, &apcContext);
  435. apcContext.apcDoneEvent.Wait();
  436. return apcContext.hasResult;
  437. #else
  438. return false;
  439. #endif
  440. }
  441. static void STDCALL WalkThreadFrameStackCallback(void* context)
  442. {
  443. WalkThreadFrameStackContext* ctx = static_cast<WalkThreadFrameStackContext*>(context);
  444. StackTrace::WalkFrameStack(ctx->callback, ctx->userContext);
  445. ctx->apcDoneEvent.Set();
  446. }
  447. void StackTrace::WalkThreadFrameStack(Il2CppThread* thread, Il2CppFrameWalkFunc callback, void* context)
  448. {
  449. #if IL2CPP_ENABLE_STACKTRACES
  450. WalkThreadFrameStackContext apcContext;
  451. apcContext.callback = callback;
  452. apcContext.userContext = context;
  453. thread->GetInternalThread()->handle->QueueUserAPC(WalkThreadFrameStackCallback, &apcContext);
  454. apcContext.apcDoneEvent.Wait();
  455. #endif
  456. }
  457. static void STDCALL GetThreadStackDepthCallback(void* context)
  458. {
  459. GetThreadStackDepthContext* ctx = static_cast<GetThreadStackDepthContext*>(context);
  460. ctx->stackDepth = static_cast<int32_t>(StackTrace::GetStackDepth());
  461. ctx->apcDoneEvent.Set();
  462. }
  463. int32_t StackTrace::GetThreadStackDepth(Il2CppThread* thread)
  464. {
  465. #if IL2CPP_ENABLE_STACKTRACES
  466. GetThreadStackDepthContext apcContext;
  467. thread->GetInternalThread()->handle->QueueUserAPC(GetThreadStackDepthCallback, &apcContext);
  468. apcContext.apcDoneEvent.Wait();
  469. return apcContext.stackDepth;
  470. #else
  471. return 0;
  472. #endif
  473. }
  474. static void STDCALL GetThreadTopFrameCallback(void* context)
  475. {
  476. GetThreadTopFrameContext* ctx = static_cast<GetThreadTopFrameContext*>(context);
  477. ctx->hasResult = StackTrace::GetTopStackFrame(*ctx->frame);
  478. ctx->apcDoneEvent.Set();
  479. }
  480. bool StackTrace::GetThreadTopStackFrame(Il2CppThread* thread, Il2CppStackFrameInfo& frame)
  481. {
  482. #if IL2CPP_ENABLE_STACKTRACES
  483. GetThreadTopFrameContext apcContext;
  484. apcContext.frame = &frame;
  485. thread->GetInternalThread()->handle->QueueUserAPC(GetThreadTopFrameCallback, &apcContext);
  486. apcContext.apcDoneEvent.Wait();
  487. return apcContext.hasResult;
  488. #else
  489. return false;
  490. #endif
  491. }
  492. }
  493. }