summaryrefslogtreecommitdiff
path: root/src/mongo/platform/backtrace.cpp
diff options
context:
space:
mode:
authorTad Marshall <tad@10gen.com>2013-06-21 13:42:41 -0400
committerTad Marshall <tad@10gen.com>2013-06-24 21:01:49 -0400
commit4232b77a2ce5aa078db6f4cf3afedf8a07efb825 (patch)
tree1befeb535eefa13e8cc46c3f9976f987e6e38e2b /src/mongo/platform/backtrace.cpp
parent1c53e2b9e90c17287664312f8fcac861d63165e4 (diff)
downloadmongo-4232b77a2ce5aa078db6f4cf3afedf8a07efb825.tar.gz
SERVER-7080 Emulate backtrace_symbols() and backtrace_symbols_fd() on Solaris 10
backtrace_symbols() returns a block of strings, each containing a symbolic representation of a location in a stack trace; i.e. a line of a stack trace. backtrace_symbols() is allowed to (and must) allocate memory and cannot be used in a signal handler. Add code to produce lines on Solaris 10 that are similar to those produced by backtrace_symbols() on Solaris 11. backtrace_symbols_fd() writes a stack trace to a specified file descriptor. backtrace_symbols_fd() must not allocate memory and may be safely used in a signal handler. Add code to produce output on Solaris 10 that is similar to that produced by backtrace_symbols_fd() on Solaris 11.
Diffstat (limited to 'src/mongo/platform/backtrace.cpp')
-rw-r--r--src/mongo/platform/backtrace.cpp82
1 files changed, 81 insertions, 1 deletions
diff --git a/src/mongo/platform/backtrace.cpp b/src/mongo/platform/backtrace.cpp
index 64d593d0157..89694425daf 100644
--- a/src/mongo/platform/backtrace.cpp
+++ b/src/mongo/platform/backtrace.cpp
@@ -18,12 +18,19 @@
#include "mongo/platform/backtrace.h"
+#include <boost/smart_ptr/scoped_array.hpp>
+#include <cstdio>
#include <dlfcn.h>
+#include <string>
#include <ucontext.h>
+#include <vector>
#include "mongo/base/init.h"
#include "mongo/base/status.h"
+using std::string;
+using std::vector;
+
namespace mongo {
namespace pal {
@@ -52,6 +59,37 @@ namespace {
size_t _count;
uintptr_t* _addresses;
};
+
+ // This function emulates a Solaris function that was added to Solaris 11 at the same time
+ // that the backtrace* functions were added. It is not important to match the function name
+ // or interface for this code, but this is a fine interface for our purposes and following
+ // an existing model seems potentially helpful ... hence the all-lowercase name with no
+ // underscores. The formatting of the output matches what Solaris 11 does; this is similar
+ // to Linux's display, but slightly different.
+ //
+ int addrtosymstr(void* address, char* outputBuffer, int outputBufferSize) {
+ Dl_info_t symbolInfo;
+ if (dladdr(address, &symbolInfo) == 0) { // no info: "[address]"
+ return snprintf(outputBuffer, outputBufferSize, "[0x%p]", address);
+ }
+ if (symbolInfo.dli_sname == NULL) {
+ return snprintf(outputBuffer, // no symbol: "filename'offset [address]"
+ outputBufferSize,
+ "%s'0x%p [0x%p]",
+ symbolInfo.dli_fname,
+ reinterpret_cast<char*>(reinterpret_cast<char*>(address) -
+ reinterpret_cast<char*>(symbolInfo.dli_fbase)),
+ address);
+ }
+ return snprintf(outputBuffer, // symbol: "filename'symbol+offset [address]"
+ outputBufferSize,
+ "%s'%s+0x%p [0x%p]",
+ symbolInfo.dli_fname,
+ symbolInfo.dli_sname,
+ reinterpret_cast<char*>(reinterpret_cast<char*>(address) -
+ reinterpret_cast<char*>(symbolInfo.dli_saddr)),
+ address);
+ }
} // namespace
typedef int (*WalkcontextCallbackFunc)(uintptr_t address, int signalNumber, void* thisContext);
@@ -72,11 +110,53 @@ namespace {
return 0;
}
+ // The API for backtrace_symbols() specifies that the caller must call free() on the char**
+ // returned by this function, and must *not* call free on the individual strings.
+ // In order to support this API, we allocate a single block of memory containing both the
+ // array of pointers to the strings and the strings themselves. Constructing this block
+ // requires two passes: one to collect the strings and calculate the required size of the
+ // combined single memory block; and a second pass to copy the strings into the block and
+ // set their pointers.
+ // The result is that we return a single memory block (allocated with malloc()) which begins
+ // with an array of pointers to strings (of count 'size'). This array is immediately
+ // followed by the strings themselves, each NUL terminated.
+ //
char** backtrace_symbols_emulation(void* const* array, int size) {
- return NULL;
+ vector<string> stringVector;
+ vector<size_t> stringLengths;
+ size_t blockSize = size * sizeof(char*);
+ size_t blockPtr = blockSize;
+ const size_t kBufferSize = 8 * 1024;
+ boost::scoped_array<char> stringBuffer(new char[kBufferSize]);
+ for (int i = 0; i < size; ++i) {
+ size_t thisLength = 1 + addrtosymstr(array[i], stringBuffer.get(), kBufferSize);
+ stringVector.push_back(string(stringBuffer.get()));
+ stringLengths.push_back(thisLength);
+ blockSize += thisLength;
+ }
+ char** singleBlock = static_cast<char**>(malloc(blockSize));
+ if (singleBlock == NULL) {
+ return NULL;
+ }
+ for (int i = 0; i < size; ++i) {
+ singleBlock[i] = reinterpret_cast<char*>(singleBlock) + blockPtr;
+ strncpy(singleBlock[i], stringVector[i].c_str(), stringLengths[i]);
+ blockPtr += stringLengths[i];
+ }
+ return singleBlock;
}
void backtrace_symbols_fd_emulation(void* const* array, int size, int fd) {
+ const int kBufferSize = 4 * 1024;
+ char stringBuffer[kBufferSize];
+ for (int i = 0; i < size; ++i) {
+ int len = addrtosymstr(array[i], stringBuffer, kBufferSize);
+ if (len > kBufferSize - 1) {
+ len = kBufferSize - 1;
+ }
+ stringBuffer[len] = '\n';
+ write(fd, stringBuffer, len + 1);
+ }
}
typedef int (*BacktraceFunc)(void** array, int size);