StackTrace.cpp 18 KB

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