summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTad Marshall <tad@10gen.com>2013-06-20 11:53:23 -0400
committerTad Marshall <tad@10gen.com>2013-07-18 14:29:19 -0400
commit66f4a37277cc2f309851e525e3392a20295cf737 (patch)
treead8f9c25f8c5ddf4829c8d71a8c442d409f1d2de
parent4d4790146b76d8e65caa9fc9c34dc4263e0539a9 (diff)
downloadmongo-66f4a37277cc2f309851e525e3392a20295cf737.tar.gz
SERVER-7080 Link to backtrace, backtrace_symbols and backtrace_symbols_fd at runtime
Do not make direct calls to backtrace, backtrace_symbols or backtrace_symbols_fd, which are present in Solaris 11 but not in Solaris 10. Instead, see if they are available in a loaded library (which will be libc.so.1) at runtime and either call them or call an emulation.
-rw-r--r--SConstruct3
-rw-r--r--src/SConscript.client1
-rw-r--r--src/mongo/platform/SConscript1
-rw-r--r--src/mongo/platform/backtrace.cpp93
-rw-r--r--src/mongo/platform/backtrace.h43
-rw-r--r--src/mongo/util/signal_handlers.cpp17
-rw-r--r--src/mongo/util/stack_introspect.cpp18
-rw-r--r--src/mongo/util/stacktrace.cpp82
8 files changed, 194 insertions, 64 deletions
diff --git a/SConstruct b/SConstruct
index 5fb0e83f492..69a374693bc 100644
--- a/SConstruct
+++ b/SConstruct
@@ -839,7 +839,8 @@ def doConfigure(myenv):
if (conf.CheckCXXHeader( "execinfo.h" ) and
conf.CheckDeclaration('backtrace', includes='#include <execinfo.h>') and
- conf.CheckDeclaration('backtrace_symbols', includes='#include <execinfo.h>')):
+ conf.CheckDeclaration('backtrace_symbols', includes='#include <execinfo.h>') and
+ conf.CheckDeclaration('backtrace_symbols_fd', includes='#include <execinfo.h>')):
myenv.Append( CPPDEFINES=[ "MONGO_HAVE_EXECINFO_BACKTRACE" ] )
diff --git a/src/SConscript.client b/src/SConscript.client
index 3f4c2ee2936..ff959e95f27 100644
--- a/src/SConscript.client
+++ b/src/SConscript.client
@@ -54,6 +54,7 @@ clientSourceBasic = [
'mongo/db/namespace.cpp',
'mongo/db/dbmessage.cpp',
'mongo/pch.cpp',
+ 'mongo/platform/backtrace.cpp',
'mongo/platform/posix_fadvise.cpp',
'mongo/platform/random.cpp',
'mongo/util/assert_util.cpp',
diff --git a/src/mongo/platform/SConscript b/src/mongo/platform/SConscript
index a5db8647c4e..99738b6693a 100644
--- a/src/mongo/platform/SConscript
+++ b/src/mongo/platform/SConscript
@@ -3,6 +3,7 @@
Import("env")
env.Library('platform', [
+ 'backtrace.cpp',
'posix_fadvise.cpp',
'random.cpp',
'strcasestr.cpp',
diff --git a/src/mongo/platform/backtrace.cpp b/src/mongo/platform/backtrace.cpp
new file mode 100644
index 00000000000..9bb3fd0283c
--- /dev/null
+++ b/src/mongo/platform/backtrace.cpp
@@ -0,0 +1,93 @@
+/* Copyright 2013 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(_WIN32)
+#if defined(__sunos__) || !defined(MONGO_HAVE_EXECINFO_BACKTRACE)
+
+#include "mongo/platform/backtrace.h"
+
+#include <dlfcn.h>
+
+#include "mongo/base/init.h"
+#include "mongo/base/status.h"
+
+namespace mongo {
+namespace pal {
+
+ int backtrace_emulation(void** array, int size) {
+ return 0;
+ }
+
+ char** backtrace_symbols_emulation(void* const* array, int size) {
+ return NULL;
+ }
+
+ void backtrace_symbols_fd_emulation(void* const* array, int size, int fd) {
+ }
+
+ typedef int (*BacktraceFunc)(void** array, int size);
+ static BacktraceFunc backtrace_switcher =
+ pal::backtrace_emulation;
+
+ typedef char** (*BacktraceSymbolsFunc)(void* const* array, int size);
+ static BacktraceSymbolsFunc backtrace_symbols_switcher =
+ pal::backtrace_symbols_emulation;
+
+ typedef void (*BacktraceSymbolsFdFunc)(void* const* array, int size, int fd);
+ static BacktraceSymbolsFdFunc backtrace_symbols_fd_switcher =
+ pal::backtrace_symbols_fd_emulation;
+
+ int backtrace(void** array, int size) {
+ return backtrace_switcher(array, size);
+ }
+
+ char** backtrace_symbols(void* const* array, int size) {
+ return backtrace_symbols_switcher(array, size);
+ }
+
+ void backtrace_symbols_fd(void* const* array, int size, int fd) {
+ backtrace_symbols_fd_switcher(array, size, fd);
+ }
+
+} // namespace pal
+
+ // 'backtrace()', 'backtrace_symbols()' and 'backtrace_symbols_fd()' on Solaris will call
+ // emulation functions if the symbols are not found
+ //
+ MONGO_INITIALIZER_GENERAL(SolarisBacktrace,
+ MONGO_NO_PREREQUISITES,
+ ("default"))(InitializerContext* context) {
+ void* functionAddress = dlsym(RTLD_DEFAULT, "backtrace");
+ if (functionAddress != NULL) {
+ pal::backtrace_switcher =
+ reinterpret_cast<pal::BacktraceFunc>(functionAddress);
+ }
+ functionAddress = dlsym(RTLD_DEFAULT, "backtrace_symbols");
+ if (functionAddress != NULL) {
+ pal::backtrace_symbols_switcher =
+ reinterpret_cast<pal::BacktraceSymbolsFunc>(functionAddress);
+ }
+ functionAddress = dlsym(RTLD_DEFAULT, "backtrace_symbols_fd");
+ if (functionAddress != NULL) {
+ pal::backtrace_symbols_fd_switcher =
+ reinterpret_cast<pal::BacktraceSymbolsFdFunc>(functionAddress);
+ }
+ return Status::OK();
+ }
+
+} // namespace mongo
+
+#endif // #if defined(__sunos__)
+#endif // #if !defined(_WIN32)
diff --git a/src/mongo/platform/backtrace.h b/src/mongo/platform/backtrace.h
new file mode 100644
index 00000000000..962cfa43119
--- /dev/null
+++ b/src/mongo/platform/backtrace.h
@@ -0,0 +1,43 @@
+/* Copyright 2013 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if !defined(_WIN32)
+#if defined(__sunos__) || !defined(MONGO_HAVE_EXECINFO_BACKTRACE)
+
+namespace mongo {
+ namespace pal {
+ int backtrace(void** array, int size);
+ char** backtrace_symbols(void* const* array, int size);
+ void backtrace_symbols_fd(void* const* array, int size, int fd);
+ } // namespace pal
+ using pal::backtrace;
+ using pal::backtrace_symbols;
+ using pal::backtrace_symbols_fd;
+} // namespace mongo
+
+#else
+
+#include <execinfo.h>
+
+namespace mongo {
+ using ::backtrace;
+ using ::backtrace_symbols;
+ using ::backtrace_symbols_fd;
+} // namespace mongo
+
+#endif
+#endif
diff --git a/src/mongo/util/signal_handlers.cpp b/src/mongo/util/signal_handlers.cpp
index 52694900448..241d824b1a0 100644
--- a/src/mongo/util/signal_handlers.cpp
+++ b/src/mongo/util/signal_handlers.cpp
@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "pch.h"
+#include "mongo/pch.h"
#include <cstdarg>
#include <cstdio>
@@ -26,20 +26,17 @@
#include <unistd.h>
#endif
-#ifdef MONGO_HAVE_EXECINFO_BACKTRACE
-#include <execinfo.h>
-#endif
-
-#include "log.h"
-#include "signal_handlers.h"
+#include "mongo/platform/backtrace.h"
+#include "mongo/util/log.h"
+#include "mongo/util/signal_handlers.h"
namespace mongo {
/*
* WARNING: PLEASE READ BEFORE CHANGING THIS MODULE
*
- * All code in this module should be singal-friendly. Before adding any system
- * call or other dependency, please make sure the latter still holds.
+ * All code in this module must be signal-friendly. Before adding any system
+ * call or other dependency, please make sure that this still holds.
*
*/
@@ -84,7 +81,7 @@ namespace mongo {
static void formattedBacktrace( int fd ) {
-#ifdef MONGO_HAVE_EXECINFO_BACKTRACE
+#if !defined(_WIN32)
int numFrames;
const int MAX_DEPTH = 20;
diff --git a/src/mongo/util/stack_introspect.cpp b/src/mongo/util/stack_introspect.cpp
index 27ebb0267cf..ce69b988bb7 100644
--- a/src/mongo/util/stack_introspect.cpp
+++ b/src/mongo/util/stack_introspect.cpp
@@ -18,22 +18,21 @@
#include "mongo/util/stack_introspect.h"
+#if !defined(_WIN32)
+
#include <cstdlib>
+#include <cxxabi.h>
#include <iostream>
-#include <string>
#include <map>
+#include <string>
#include <vector>
+#include "mongo/platform/backtrace.h"
#include "mongo/util/concurrency/mutex.h"
#include "mongo/util/text.h"
using namespace std;
-#ifdef MONGO_HAVE_EXECINFO_BACKTRACE
-
-#include <execinfo.h>
-#include <cxxabi.h>
-
namespace mongo {
namespace {
@@ -106,7 +105,7 @@ namespace mongo {
bool inConstructorChain( bool printOffending ){
void* b[maxBackTraceFrames];
- int size = ::backtrace( b, maxBackTraceFrames );
+ int size = backtrace( b, maxBackTraceFrames );
char** strings = 0;
@@ -122,7 +121,7 @@ namespace mongo {
}
if ( ! strings )
- strings = ::backtrace_symbols( b, size );
+ strings = backtrace_symbols( b, size );
string symbol = strings[i];
@@ -176,5 +175,4 @@ namespace mongo {
bool inConstructorChainSupported() { return false; }
}
-#endif // defined(MONGO_HAVE_EXECINFO_BACKTRACE)
-
+#endif // #if !defined(_WIN32)
diff --git a/src/mongo/util/stacktrace.cpp b/src/mongo/util/stacktrace.cpp
index ab405c9a717..37783fc0ef4 100644
--- a/src/mongo/util/stacktrace.cpp
+++ b/src/mongo/util/stacktrace.cpp
@@ -11,53 +11,18 @@
#include "mongo/util/log.h"
#ifdef _WIN32
-#include <sstream>
-#include <stdio.h>
#include <boost/filesystem/operations.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
+#include <sstream>
+#include <stdio.h>
#include "mongo/platform/windows_basic.h"
#include <DbgHelp.h>
#include "mongo/util/assert_util.h"
+#else
+#include "mongo/platform/backtrace.h"
#endif
-#ifdef MONGO_HAVE_EXECINFO_BACKTRACE
-
-#include <execinfo.h>
-
-namespace mongo {
- static const int maxBackTraceFrames = 20;
-
- /**
- * Print a stack backtrace for the current thread to the specified ostream.
- *
- * @param os ostream& to receive printed stack backtrace
- */
- void printStackTrace( std::ostream& os ) {
-
- void *b[maxBackTraceFrames];
-
- int size = ::backtrace( b, maxBackTraceFrames );
- for ( int i = 0; i < size; i++ )
- os << std::hex << b[i] << std::dec << ' ';
- os << std::endl;
-
- char **strings;
-
- strings = ::backtrace_symbols( b, size );
- if (strings == NULL) {
- const int err = errno;
- os << "Unable to collect backtrace symbols (" << errnoWithDescription(err) << ")"
- << std::endl;
- return;
- }
- for ( int i = 0; i < size; i++ )
- os << ' ' << strings[i] << '\n';
- os.flush();
- ::free( strings );
- }
-}
-
-#elif defined(_WIN32)
+#if defined(_WIN32)
namespace mongo {
@@ -306,12 +271,43 @@ namespace mongo {
}
}
-
#else
namespace mongo {
- void printStackTrace( std::ostream &os ) {}
+ static const int maxBackTraceFrames = 20;
+
+ /**
+ * Print a stack backtrace for the current thread to the specified ostream.
+ *
+ * @param os ostream& to receive printed stack backtrace
+ */
+ void printStackTrace( std::ostream& os ) {
+
+ void* addresses[maxBackTraceFrames];
+
+ int addressCount = backtrace(addresses, maxBackTraceFrames);
+ if (addressCount == 0) {
+ const int err = errno;
+ os << "Unable to collect backtrace addresses (" << errnoWithDescription(err) << ")"
+ << std::endl;
+ return;
+ }
+ for (int i = 0; i < addressCount; i++)
+ os << std::hex << addresses[i] << std::dec << ' ';
+ os << std::endl;
+
+ char** backtraceStrings = backtrace_symbols(addresses, addressCount);
+ if (backtraceStrings == NULL) {
+ const int err = errno;
+ os << "Unable to collect backtrace symbols (" << errnoWithDescription(err) << ")"
+ << std::endl;
+ return;
+ }
+ for (int i = 0; i < addressCount; i++)
+ os << ' ' << backtraceStrings[i] << '\n';
+ os.flush();
+ free(backtraceStrings);
+ }
}
#endif
-