summaryrefslogtreecommitdiff
path: root/src/mongo/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/platform')
-rw-r--r--src/mongo/platform/backtrace.cpp42
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;
}