1
/* Copyright 2013 10gen Inc.
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
* you may not use this file except in compliance with the License.
5
* You may obtain a copy of the License at
7
* http://www.apache.org/licenses/LICENSE-2.0
9
* Unless required by applicable law or agreed to in writing, software
10
* distributed under the License is distributed on an "AS IS" BASIS,
11
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
* See the License for the specific language governing permissions and
13
* limitations under the License.
17
#if defined(__sunos__) || !defined(MONGO_HAVE_EXECINFO_BACKTRACE)
19
#include "mongo/platform/backtrace.h"
21
#include <boost/smart_ptr/scoped_array.hpp>
28
#include "mongo/base/init.h"
29
#include "mongo/base/status.h"
38
class WalkcontextCallback {
40
WalkcontextCallback(uintptr_t* array, int size)
45
// This callback function is called from C code, and so must not throw exceptions
47
static int callbackFunction(uintptr_t address,
49
WalkcontextCallback* thisContext) {
50
if (thisContext->_position < thisContext->_count) {
51
thisContext->_addresses[thisContext->_position++] = address;
56
int getCount() const { return static_cast<int>(_position); }
60
uintptr_t* _addresses;
63
// This function emulates a Solaris function that was added to Solaris 11 at the same time
64
// that the backtrace* functions were added. It is not important to match the function name
65
// or interface for this code, but this is a fine interface for our purposes and following
66
// an existing model seems potentially helpful ... hence the all-lowercase name with no
67
// underscores. The formatting of the output matches what Solaris 11 does; this is similar
68
// to Linux's display, but slightly different.
70
int addrtosymstr(void* address, char* outputBuffer, int outputBufferSize) {
72
if (dladdr(address, &symbolInfo) == 0) { // no info: "[address]"
73
return snprintf(outputBuffer, outputBufferSize, "[0x%p]", address);
75
if (symbolInfo.dli_sname == NULL) {
76
return snprintf(outputBuffer, // no symbol: "filename'offset [address]"
80
reinterpret_cast<char*>(reinterpret_cast<char*>(address) -
81
reinterpret_cast<char*>(symbolInfo.dli_fbase)),
84
return snprintf(outputBuffer, // symbol: "filename'symbol+offset [address]"
89
reinterpret_cast<char*>(reinterpret_cast<char*>(address) -
90
reinterpret_cast<char*>(symbolInfo.dli_saddr)),
95
typedef int (*WalkcontextCallbackFunc)(uintptr_t address, int signalNumber, void* thisContext);
97
int backtrace_emulation(void** array, int size) {
98
WalkcontextCallback walkcontextCallback(reinterpret_cast<uintptr_t*>(array), size);
100
if (getcontext(&context) != 0) {
103
int wcReturn = walkcontext(
105
reinterpret_cast<WalkcontextCallbackFunc>(WalkcontextCallback::callbackFunction),
106
static_cast<void*>(&walkcontextCallback));
108
return walkcontextCallback.getCount();
113
// The API for backtrace_symbols() specifies that the caller must call free() on the char**
114
// returned by this function, and must *not* call free on the individual strings.
115
// In order to support this API, we allocate a single block of memory containing both the
116
// array of pointers to the strings and the strings themselves. Constructing this block
117
// requires two passes: one to collect the strings and calculate the required size of the
118
// combined single memory block; and a second pass to copy the strings into the block and
119
// set their pointers.
120
// The result is that we return a single memory block (allocated with malloc()) which begins
121
// with an array of pointers to strings (of count 'size'). This array is immediately
122
// followed by the strings themselves, each NUL terminated.
124
char** backtrace_symbols_emulation(void* const* array, int size) {
125
vector<string> stringVector;
126
vector<size_t> stringLengths;
127
size_t blockSize = size * sizeof(char*);
128
size_t blockPtr = blockSize;
129
const size_t kBufferSize = 8 * 1024;
130
boost::scoped_array<char> stringBuffer(new char[kBufferSize]);
131
for (int i = 0; i < size; ++i) {
132
size_t thisLength = 1 + addrtosymstr(array[i], stringBuffer.get(), kBufferSize);
133
stringVector.push_back(string(stringBuffer.get()));
134
stringLengths.push_back(thisLength);
135
blockSize += thisLength;
137
char** singleBlock = static_cast<char**>(malloc(blockSize));
138
if (singleBlock == NULL) {
141
for (int i = 0; i < size; ++i) {
142
singleBlock[i] = reinterpret_cast<char*>(singleBlock) + blockPtr;
143
strncpy(singleBlock[i], stringVector[i].c_str(), stringLengths[i]);
144
blockPtr += stringLengths[i];
149
void backtrace_symbols_fd_emulation(void* const* array, int size, int fd) {
150
const int kBufferSize = 4 * 1024;
151
char stringBuffer[kBufferSize];
152
for (int i = 0; i < size; ++i) {
153
int len = addrtosymstr(array[i], stringBuffer, kBufferSize);
154
if (len > kBufferSize - 1) {
155
len = kBufferSize - 1;
157
stringBuffer[len] = '\n';
158
write(fd, stringBuffer, len + 1);
162
typedef int (*BacktraceFunc)(void** array, int size);
163
static BacktraceFunc backtrace_switcher =
164
pal::backtrace_emulation;
166
typedef char** (*BacktraceSymbolsFunc)(void* const* array, int size);
167
static BacktraceSymbolsFunc backtrace_symbols_switcher =
168
pal::backtrace_symbols_emulation;
170
typedef void (*BacktraceSymbolsFdFunc)(void* const* array, int size, int fd);
171
static BacktraceSymbolsFdFunc backtrace_symbols_fd_switcher =
172
pal::backtrace_symbols_fd_emulation;
174
int backtrace(void** array, int size) {
175
return backtrace_switcher(array, size);
178
char** backtrace_symbols(void* const* array, int size) {
179
return backtrace_symbols_switcher(array, size);
182
void backtrace_symbols_fd(void* const* array, int size, int fd) {
183
backtrace_symbols_fd_switcher(array, size, fd);
188
// 'backtrace()', 'backtrace_symbols()' and 'backtrace_symbols_fd()' on Solaris will call
189
// emulation functions if the symbols are not found
191
MONGO_INITIALIZER_GENERAL(SolarisBacktrace,
192
MONGO_NO_PREREQUISITES,
193
("default"))(InitializerContext* context) {
194
void* functionAddress = dlsym(RTLD_DEFAULT, "backtrace");
195
if (functionAddress != NULL) {
196
pal::backtrace_switcher =
197
reinterpret_cast<pal::BacktraceFunc>(functionAddress);
199
functionAddress = dlsym(RTLD_DEFAULT, "backtrace_symbols");
200
if (functionAddress != NULL) {
201
pal::backtrace_symbols_switcher =
202
reinterpret_cast<pal::BacktraceSymbolsFunc>(functionAddress);
204
functionAddress = dlsym(RTLD_DEFAULT, "backtrace_symbols_fd");
205
if (functionAddress != NULL) {
206
pal::backtrace_symbols_fd_switcher =
207
reinterpret_cast<pal::BacktraceSymbolsFdFunc>(functionAddress);
214
#endif // #if defined(__sunos__)
215
#endif // #if !defined(_WIN32)