diff options
author | Tad Marshall <tad@10gen.com> | 2013-06-21 13:42:41 -0400 |
---|---|---|
committer | Tad Marshall <tad@10gen.com> | 2013-06-24 21:01:49 -0400 |
commit | 4232b77a2ce5aa078db6f4cf3afedf8a07efb825 (patch) | |
tree | 1befeb535eefa13e8cc46c3f9976f987e6e38e2b /src/mongo/platform/backtrace.cpp | |
parent | 1c53e2b9e90c17287664312f8fcac861d63165e4 (diff) | |
download | mongo-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.cpp | 82 |
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); |