diff options
Diffstat (limited to 'src/mongo/platform/backtrace.cpp')
-rw-r--r-- | src/mongo/platform/backtrace.cpp | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/src/mongo/platform/backtrace.cpp b/src/mongo/platform/backtrace.cpp index 9bb3fd0283c..64d593d0157 100644 --- a/src/mongo/platform/backtrace.cpp +++ b/src/mongo/platform/backtrace.cpp @@ -19,6 +19,7 @@ #include "mongo/platform/backtrace.h" #include <dlfcn.h> +#include <ucontext.h> #include "mongo/base/init.h" #include "mongo/base/status.h" @@ -26,7 +27,48 @@ namespace mongo { namespace pal { +namespace { + class WalkcontextCallback { + public: + WalkcontextCallback(uintptr_t* array, int size) + : _position(0), + _count(size), + _addresses(array) {} + + // This callback function is called from C code, and so must not throw exceptions + // + static int callbackFunction(uintptr_t address, + int signalNumber, + WalkcontextCallback* thisContext) { + if (thisContext->_position < thisContext->_count) { + thisContext->_addresses[thisContext->_position++] = address; + return 0; + } + return 1; + } + int getCount() const { return static_cast<int>(_position); } + private: + size_t _position; + size_t _count; + uintptr_t* _addresses; + }; +} // namespace + + typedef int (*WalkcontextCallbackFunc)(uintptr_t address, int signalNumber, void* thisContext); + int backtrace_emulation(void** array, int size) { + WalkcontextCallback walkcontextCallback(reinterpret_cast<uintptr_t*>(array), size); + ucontext_t context; + if (getcontext(&context) != 0) { + return 0; + } + int wcReturn = walkcontext( + &context, + reinterpret_cast<WalkcontextCallbackFunc>(WalkcontextCallback::callbackFunction), + static_cast<void*>(&walkcontextCallback)); + if (wcReturn == 0) { + return walkcontextCallback.getCount(); + } return 0; } |