~ubuntu-branches/ubuntu/wily/mongodb/wily

« back to all changes in this revision

Viewing changes to src/mongo/platform/backtrace.cpp

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-26 09:41:32 UTC
  • mfrom: (1.2.25)
  • Revision ID: package-import@ubuntu.com-20130826094132-8cknfm4syxyip1zt
Tags: 1:2.4.6-0ubuntu1
* New upstream point release.
* d/control,d/tests/*: Add autopkgtests for server process and client
  shell functionality.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*    Copyright 2013 10gen Inc.
 
2
 *
 
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
 
6
 *
 
7
 *    http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
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.
 
14
 */
 
15
 
 
16
#if !defined(_WIN32)
 
17
#if defined(__sunos__) || !defined(MONGO_HAVE_EXECINFO_BACKTRACE)
 
18
 
 
19
#include "mongo/platform/backtrace.h"
 
20
 
 
21
#include <boost/smart_ptr/scoped_array.hpp>
 
22
#include <cstdio>
 
23
#include <dlfcn.h>
 
24
#include <string>
 
25
#include <ucontext.h>
 
26
#include <vector>
 
27
 
 
28
#include "mongo/base/init.h"
 
29
#include "mongo/base/status.h"
 
30
 
 
31
using std::string;
 
32
using std::vector;
 
33
 
 
34
namespace mongo {
 
35
namespace pal {
 
36
 
 
37
namespace {
 
38
    class WalkcontextCallback {
 
39
    public:
 
40
        WalkcontextCallback(uintptr_t* array, int size)
 
41
            : _position(0),
 
42
              _count(size),
 
43
              _addresses(array) {}
 
44
 
 
45
        // This callback function is called from C code, and so must not throw exceptions
 
46
        //
 
47
        static int callbackFunction(uintptr_t address,
 
48
                                    int signalNumber,
 
49
                                    WalkcontextCallback* thisContext) {
 
50
            if (thisContext->_position < thisContext->_count) {
 
51
                thisContext->_addresses[thisContext->_position++] = address;
 
52
                return 0;
 
53
            }
 
54
            return 1;
 
55
        }
 
56
        int getCount() const { return static_cast<int>(_position); }
 
57
    private:
 
58
        size_t _position;
 
59
        size_t _count;
 
60
        uintptr_t* _addresses;
 
61
    };
 
62
 
 
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.
 
69
    //
 
70
    int addrtosymstr(void* address, char* outputBuffer, int outputBufferSize) {
 
71
        Dl_info_t symbolInfo;
 
72
        if (dladdr(address, &symbolInfo) == 0) {    // no info: "[address]"
 
73
            return snprintf(outputBuffer, outputBufferSize, "[0x%p]", address);
 
74
        }
 
75
        if (symbolInfo.dli_sname == NULL) {
 
76
            return snprintf(outputBuffer,           // no symbol: "filename'offset [address]"
 
77
                            outputBufferSize,
 
78
                            "%s'0x%p [0x%p]",
 
79
                            symbolInfo.dli_fname,
 
80
                            reinterpret_cast<char*>(reinterpret_cast<char*>(address) -
 
81
                                                    reinterpret_cast<char*>(symbolInfo.dli_fbase)),
 
82
                            address);
 
83
        }
 
84
        return snprintf(outputBuffer,               // symbol: "filename'symbol+offset [address]"
 
85
                        outputBufferSize,
 
86
                        "%s'%s+0x%p [0x%p]",
 
87
                        symbolInfo.dli_fname,
 
88
                        symbolInfo.dli_sname,
 
89
                        reinterpret_cast<char*>(reinterpret_cast<char*>(address) -
 
90
                                                reinterpret_cast<char*>(symbolInfo.dli_saddr)),
 
91
                        address);
 
92
    }
 
93
} // namespace
 
94
 
 
95
    typedef int (*WalkcontextCallbackFunc)(uintptr_t address, int signalNumber, void* thisContext);
 
96
 
 
97
    int backtrace_emulation(void** array, int size) {
 
98
        WalkcontextCallback walkcontextCallback(reinterpret_cast<uintptr_t*>(array), size);
 
99
        ucontext_t context;
 
100
        if (getcontext(&context) != 0) {
 
101
            return 0;
 
102
        }
 
103
        int wcReturn = walkcontext(
 
104
                &context,
 
105
                reinterpret_cast<WalkcontextCallbackFunc>(WalkcontextCallback::callbackFunction),
 
106
                static_cast<void*>(&walkcontextCallback));
 
107
        if (wcReturn == 0) {
 
108
            return walkcontextCallback.getCount();
 
109
        }
 
110
        return 0;
 
111
    }
 
112
 
 
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.
 
123
    //
 
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;
 
136
        }
 
137
        char** singleBlock = static_cast<char**>(malloc(blockSize));
 
138
        if (singleBlock == NULL) {
 
139
            return NULL;
 
140
        }
 
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];
 
145
        }
 
146
        return singleBlock;
 
147
    }
 
148
 
 
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;
 
156
            }
 
157
            stringBuffer[len] = '\n';
 
158
            write(fd, stringBuffer, len + 1);
 
159
        }
 
160
    }
 
161
 
 
162
    typedef int (*BacktraceFunc)(void** array, int size);
 
163
    static BacktraceFunc backtrace_switcher =
 
164
            pal::backtrace_emulation;
 
165
 
 
166
    typedef char** (*BacktraceSymbolsFunc)(void* const* array, int size);
 
167
    static BacktraceSymbolsFunc backtrace_symbols_switcher =
 
168
            pal::backtrace_symbols_emulation;
 
169
 
 
170
    typedef void (*BacktraceSymbolsFdFunc)(void* const* array, int size, int fd);
 
171
    static BacktraceSymbolsFdFunc backtrace_symbols_fd_switcher =
 
172
            pal::backtrace_symbols_fd_emulation;
 
173
 
 
174
    int backtrace(void** array, int size) {
 
175
        return backtrace_switcher(array, size);
 
176
    }
 
177
 
 
178
    char** backtrace_symbols(void* const* array, int size) {
 
179
        return backtrace_symbols_switcher(array, size);
 
180
    }
 
181
 
 
182
    void backtrace_symbols_fd(void* const* array, int size, int fd) {
 
183
        backtrace_symbols_fd_switcher(array, size, fd);
 
184
    }
 
185
 
 
186
} // namespace pal
 
187
 
 
188
    // 'backtrace()', 'backtrace_symbols()' and 'backtrace_symbols_fd()' on Solaris will call
 
189
    // emulation functions if the symbols are not found
 
190
    //
 
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);
 
198
        }
 
199
        functionAddress = dlsym(RTLD_DEFAULT, "backtrace_symbols");
 
200
        if (functionAddress != NULL) {
 
201
            pal::backtrace_symbols_switcher =
 
202
                    reinterpret_cast<pal::BacktraceSymbolsFunc>(functionAddress);
 
203
        }
 
204
        functionAddress = dlsym(RTLD_DEFAULT, "backtrace_symbols_fd");
 
205
        if (functionAddress != NULL) {
 
206
            pal::backtrace_symbols_fd_switcher =
 
207
                    reinterpret_cast<pal::BacktraceSymbolsFdFunc>(functionAddress);
 
208
        }
 
209
        return Status::OK();
 
210
    }
 
211
 
 
212
} // namespace mongo
 
213
 
 
214
#endif // #if defined(__sunos__)
 
215
#endif // #if !defined(_WIN32)