StackTrace.cpp 18 KB

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