123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- #include "il2cpp-config.h"
- #include "StackTrace.h"
- #include "il2cpp-object-internals.h"
- #include "os/Event.h"
- #include "os/StackTrace.h"
- #include "os/Thread.h"
- #include "os/ThreadLocalValue.h"
- #include "os/Image.h"
- #include "vm/Method.h"
- #include "vm/Thread.h"
- #include "vm/Type.h"
- #include "vm-utils/Debugger.h"
- #include "vm-utils/NativeSymbol.h"
- #include "vm-utils/DebugSymbolReader.h"
- #include "vm-utils/Debugger.h"
-
- #include <map>
- #include <cstdio>
-
- namespace il2cpp
- {
- namespace vm
- {
- #if IL2CPP_ENABLE_STACKTRACES
-
- class CachedInfo
- {
- int32_t m_depth;
- const void* m_stackPointer;
- public:
- CachedInfo() : m_depth(INT_MAX), m_stackPointer(NULL) {}
- void Update(int32_t depth, const void *stackPointer)
- {
- m_depth = depth;
- m_stackPointer = stackPointer;
- }
-
- bool CheckCondition(int32_t depth, const void *stackPointer) const
- {
- // We can use cached value if stack pointer is the same and not NULL, and 'depth' has been incremented since previous call
- return m_stackPointer != NULL && stackPointer == m_stackPointer && depth - 1 == m_depth;
- }
- };
-
- class MethodStack
- {
- protected:
- os::ThreadLocalValue s_StackFrames;
- os::ThreadLocalValue s_StoredCachedInfo;
-
- inline StackFrames* GetStackFramesRaw()
- {
- StackFrames* stackFrames = NULL;
-
- os::ErrorCode result = s_StackFrames.GetValue(reinterpret_cast<void**>(&stackFrames));
- Assert(result == os::kErrorCodeSuccess);
-
- return stackFrames;
- }
-
- inline CachedInfo* GetStoredCachedInfoRaw()
- {
- CachedInfo* storedCachedInfo = NULL;
-
- os::ErrorCode result = s_StoredCachedInfo.GetValue(reinterpret_cast<void**>(&storedCachedInfo));
- Assert(result == os::kErrorCodeSuccess);
-
- return storedCachedInfo;
- }
-
- public:
- inline void InitializeForCurrentThread()
- {
- if (GetStackFramesRaw() != NULL)
- return;
-
- StackFrames* stackFrames = new StackFrames();
- stackFrames->reserve(64);
-
- os::ErrorCode result = s_StackFrames.SetValue(stackFrames);
- Assert(result == os::kErrorCodeSuccess);
-
- CachedInfo* cachedInfo = new CachedInfo();
- result = s_StoredCachedInfo.SetValue(cachedInfo);
- Assert(result == os::kErrorCodeSuccess);
- }
-
- inline void CleanupForCurrentThread()
- {
- StackFrames* frames = GetStackFramesRaw();
-
- if (frames == NULL)
- return;
-
- delete frames;
-
- CachedInfo* cachedInfo = GetStoredCachedInfoRaw();
-
- if (cachedInfo == NULL)
- return;
-
- delete cachedInfo;
-
- os::ErrorCode result = s_StackFrames.SetValue(NULL);
- Assert(result == os::kErrorCodeSuccess);
- result = s_StoredCachedInfo.SetValue(NULL);
- Assert(result == os::kErrorCodeSuccess);
- }
- };
-
- #if IL2CPP_ENABLE_STACKTRACE_SENTRIES
-
- class StacktraceSentryMethodStack : public MethodStack
- {
- public:
- inline const StackFrames* GetStackFrames()
- {
- return GetStackFramesRaw();
- }
-
- inline const StackFrames* GetCachedStackFrames(int32_t depth, const void* stackPointer)
- {
- return GetStackFrames();
- }
-
- inline bool GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
- {
- const StackFrames& frames = *GetStackFramesRaw();
-
- if (static_cast<int>(frames.size()) + depth < 1)
- return false;
-
- frame = frames[frames.size() - 1 + depth];
- return true;
- }
-
- inline void PushFrame(Il2CppStackFrameInfo& frame)
- {
- GetStackFramesRaw()->push_back(frame);
- }
-
- inline void PopFrame()
- {
- StackFrames* stackFrames = GetStackFramesRaw();
- stackFrames->pop_back();
- }
-
- inline const void* GetStackPointer()
- {
- return nullptr;
- }
- };
-
- #endif // IL2CPP_ENABLE_STACKTRACE_SENTRIES
-
- #if IL2CPP_ENABLE_NATIVE_STACKTRACES
-
- #if IL2CPP_MONO_DEBUGGER
- class DebuggerMethodStack : public MethodStack
- {
- public:
- inline const StackFrames* GetStackFrames()
- {
- StackFrames* stackFrames = GetStackFramesRaw();
- if (stackFrames == NULL)
- return stackFrames;
- stackFrames->clear();
-
- utils::Debugger::GetStackFrames(stackFrames);
-
- return stackFrames;
- }
-
- inline const StackFrames* GetCachedStackFrames(int32_t depth, const void* stackPointer)
- {
- CachedInfo* cachedInfo = GetStoredCachedInfoRaw();
- const StackFrames* stackFrames = cachedInfo->CheckCondition(depth, stackPointer) ? GetStackFramesRaw() : GetStackFrames();
- cachedInfo->Update(depth, stackPointer);
- return stackFrames;
- }
-
- inline bool GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
- {
- const StackFrames& frames = *GetStackFrames();
-
- if (static_cast<int>(frames.size()) + depth < 1)
- return false;
-
- frame = frames[frames.size() - 1 + depth];
- return true;
- }
-
- inline void PushFrame(Il2CppStackFrameInfo& frame)
- {
- }
-
- inline void PopFrame()
- {
- }
-
- inline const void* GetStackPointer()
- {
- return nullptr;
- }
- };
- #else
- class NativeMethodStack : public MethodStack
- {
- static bool GetStackFramesCallback(Il2CppMethodPointer frame, void* context)
- {
- const MethodInfo* method = il2cpp::utils::NativeSymbol::GetMethodFromNativeSymbol(frame);
- StackFrames* stackFrames = static_cast<StackFrames*>(context);
-
- if (method != NULL)
- {
- bool frames_added = il2cpp::utils::DebugSymbolReader::AddStackFrames(reinterpret_cast<void*>(frame), stackFrames);
-
- if (!frames_added)
- {
- Il2CppStackFrameInfo frameInfo = { 0 };
- frameInfo.method = method;
- frameInfo.raw_ip = reinterpret_cast<uintptr_t>(frame) - reinterpret_cast<uintptr_t>(os::Image::GetImageBase());
- stackFrames->push_back(frameInfo);
- }
- }
-
- return true;
- }
-
- struct GetStackFrameAtContext
- {
- int32_t currentDepth;
- const MethodInfo* method;
- };
-
- static bool GetStackFrameAtCallback(Il2CppMethodPointer frame, void* context)
- {
- const MethodInfo* method = il2cpp::utils::NativeSymbol::GetMethodFromNativeSymbol(frame);
- GetStackFrameAtContext* ctx = static_cast<GetStackFrameAtContext*>(context);
-
- if (method != NULL)
- {
- if (ctx->currentDepth == 0)
- {
- ctx->method = method;
- return false;
- }
-
- ctx->currentDepth++;
- }
-
- return true;
- }
-
- public:
- inline const StackFrames* GetStackFrames()
- {
- StackFrames* stackFrames = GetStackFramesRaw();
- if (stackFrames == NULL)
- return stackFrames;
- stackFrames->clear();
-
- os::StackTrace::WalkStack(&NativeMethodStack::GetStackFramesCallback, stackFrames, os::StackTrace::kFirstCalledToLastCalled);
-
- return stackFrames;
- }
-
- // Avoiding calling GetStackFrames() method for the same stack trace with incremented 'depth' value
- inline const StackFrames* GetCachedStackFrames(int32_t depth, const void* stackPointer)
- {
- CachedInfo* cachedInfo = GetStoredCachedInfoRaw();
- const StackFrames* stackFrames = cachedInfo->CheckCondition(depth, stackPointer) ? GetStackFramesRaw() : GetStackFrames();
- cachedInfo->Update(depth, stackPointer);
- return stackFrames;
- }
-
- inline bool GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
- {
- GetStackFrameAtContext context = { depth, NULL };
-
- os::StackTrace::WalkStack(&NativeMethodStack::GetStackFrameAtCallback, &context, os::StackTrace::kLastCalledToFirstCalled);
-
- if (context.method != NULL)
- {
- frame.method = context.method;
- return true;
- }
-
- return false;
- }
-
- inline void PushFrame(Il2CppStackFrameInfo& frame)
- {
- }
-
- inline void PopFrame()
- {
- }
-
- // Returns SP value or nullptr if not implemented
- inline const void* GetStackPointer()
- {
- return os::StackTrace::GetStackPointer();
- }
- };
- #endif // IL2CPP_MONO_DEBUGGER
-
- #endif // IL2CPP_ENABLE_NATIVE_STACKTRACES
-
- #else
-
- static StackFrames s_EmptyStack;
-
- class NoOpMethodStack
- {
- public:
- inline void InitializeForCurrentThread()
- {
- }
-
- inline void CleanupForCurrentThread()
- {
- }
-
- inline const StackFrames* GetStackFrames()
- {
- return &s_EmptyStack;
- }
-
- inline const StackFrames* GetCachedStackFrames(int32_t depth, const void* stackPointer)
- {
- return GetStackFrames();
- }
-
- inline bool GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
- {
- return false;
- }
-
- inline void PushFrame(Il2CppStackFrameInfo& frame)
- {
- }
-
- inline void PopFrame()
- {
- }
-
- inline const void* GetStackPointer()
- {
- return nullptr;
- }
- };
-
- #endif // IL2CPP_ENABLE_STACKTRACES
-
- #if IL2CPP_ENABLE_STACKTRACES
-
- #if IL2CPP_ENABLE_STACKTRACE_SENTRIES
-
- StacktraceSentryMethodStack s_MethodStack;
-
- #elif IL2CPP_ENABLE_NATIVE_STACKTRACES
-
- #if IL2CPP_MONO_DEBUGGER
- DebuggerMethodStack s_MethodStack;
- #else
- NativeMethodStack s_MethodStack;
- #endif
-
- #endif
-
- #else
-
- NoOpMethodStack s_MethodStack;
-
- #endif // IL2CPP_ENABLE_STACKTRACES
-
- // Current thread functions
-
- void StackTrace::InitializeStackTracesForCurrentThread()
- {
- s_MethodStack.InitializeForCurrentThread();
- }
-
- void StackTrace::CleanupStackTracesForCurrentThread()
- {
- s_MethodStack.CleanupForCurrentThread();
- }
-
- const StackFrames* StackTrace::GetStackFrames()
- {
- return s_MethodStack.GetStackFrames();
- }
-
- const StackFrames* StackTrace::GetCachedStackFrames(int32_t depth)
- {
- return s_MethodStack.GetCachedStackFrames(depth, GetStackPointer());
- }
-
- bool StackTrace::GetStackFrameAt(int32_t depth, Il2CppStackFrameInfo& frame)
- {
- Assert(depth <= 0 && "Frame depth must be 0 or less");
- return s_MethodStack.GetStackFrameAt(depth, frame);
- }
-
- void StackTrace::WalkFrameStack(Il2CppFrameWalkFunc callback, void* context)
- {
- const StackFrames& frames = *GetStackFrames();
-
- for (StackFrames::const_iterator it = frames.begin(); it != frames.end(); it++)
- callback(&*it, context);
- }
-
- void StackTrace::PushFrame(Il2CppStackFrameInfo& frame)
- {
- s_MethodStack.PushFrame(frame);
- }
-
- void StackTrace::PopFrame()
- {
- s_MethodStack.PopFrame();
- }
-
- const void* StackTrace::GetStackPointer()
- {
- return s_MethodStack.GetStackPointer();
- }
-
- // Remote thread functions
-
- struct GetThreadFrameAtContext
- {
- il2cpp::os::Event apcDoneEvent;
- int32_t depth;
- Il2CppStackFrameInfo* frame;
- bool hasResult;
- };
-
- struct WalkThreadFrameStackContext
- {
- il2cpp::os::Event apcDoneEvent;
- Il2CppFrameWalkFunc callback;
- void* userContext;
- };
-
- struct GetThreadStackDepthContext
- {
- il2cpp::os::Event apcDoneEvent;
- int32_t stackDepth;
- };
-
- struct GetThreadTopFrameContext
- {
- il2cpp::os::Event apcDoneEvent;
- Il2CppStackFrameInfo* frame;
- bool hasResult;
- };
-
- static void STDCALL GetThreadFrameAtCallback(void* context)
- {
- GetThreadFrameAtContext* ctx = static_cast<GetThreadFrameAtContext*>(context);
-
- ctx->hasResult = StackTrace::GetStackFrameAt(ctx->depth, *ctx->frame);
- ctx->apcDoneEvent.Set();
- }
-
- bool StackTrace::GetThreadStackFrameAt(Il2CppThread* thread, int32_t depth, Il2CppStackFrameInfo& frame)
- {
- #if IL2CPP_ENABLE_STACKTRACES
- GetThreadFrameAtContext apcContext;
-
- apcContext.depth = depth;
- apcContext.frame = &frame;
-
- thread->GetInternalThread()->handle->QueueUserAPC(GetThreadFrameAtCallback, &apcContext);
- apcContext.apcDoneEvent.Wait();
-
- return apcContext.hasResult;
- #else
- return false;
- #endif
- }
-
- static void STDCALL WalkThreadFrameStackCallback(void* context)
- {
- WalkThreadFrameStackContext* ctx = static_cast<WalkThreadFrameStackContext*>(context);
-
- StackTrace::WalkFrameStack(ctx->callback, ctx->userContext);
- ctx->apcDoneEvent.Set();
- }
-
- void StackTrace::WalkThreadFrameStack(Il2CppThread* thread, Il2CppFrameWalkFunc callback, void* context)
- {
- #if IL2CPP_ENABLE_STACKTRACES
- WalkThreadFrameStackContext apcContext;
-
- apcContext.callback = callback;
- apcContext.userContext = context;
-
- thread->GetInternalThread()->handle->QueueUserAPC(WalkThreadFrameStackCallback, &apcContext);
- apcContext.apcDoneEvent.Wait();
- #endif
- }
-
- static void STDCALL GetThreadStackDepthCallback(void* context)
- {
- GetThreadStackDepthContext* ctx = static_cast<GetThreadStackDepthContext*>(context);
-
- ctx->stackDepth = static_cast<int32_t>(StackTrace::GetStackDepth());
- ctx->apcDoneEvent.Set();
- }
-
- int32_t StackTrace::GetThreadStackDepth(Il2CppThread* thread)
- {
- #if IL2CPP_ENABLE_STACKTRACES
- GetThreadStackDepthContext apcContext;
-
- thread->GetInternalThread()->handle->QueueUserAPC(GetThreadStackDepthCallback, &apcContext);
- apcContext.apcDoneEvent.Wait();
-
- return apcContext.stackDepth;
- #else
- return 0;
- #endif
- }
-
- static void STDCALL GetThreadTopFrameCallback(void* context)
- {
- GetThreadTopFrameContext* ctx = static_cast<GetThreadTopFrameContext*>(context);
-
- ctx->hasResult = StackTrace::GetTopStackFrame(*ctx->frame);
- ctx->apcDoneEvent.Set();
- }
-
- bool StackTrace::GetThreadTopStackFrame(Il2CppThread* thread, Il2CppStackFrameInfo& frame)
- {
- #if IL2CPP_ENABLE_STACKTRACES
- GetThreadTopFrameContext apcContext;
- apcContext.frame = &frame;
-
- thread->GetInternalThread()->handle->QueueUserAPC(GetThreadTopFrameCallback, &apcContext);
- apcContext.apcDoneEvent.Wait();
-
- return apcContext.hasResult;
- #else
- return false;
- #endif
- }
- }
- }
|