diff options
| author | Ben Murdoch <benm@google.com> | 2010-11-18 18:32:45 +0000 |
|---|---|---|
| committer | Ben Murdoch <benm@google.com> | 2010-11-18 18:38:07 +0000 |
| commit | 513209b27ff55e2841eac0e4120199c23acce758 (patch) | |
| tree | aeba30bb08c5f47c57003544e378a377c297eee6 /base/debug/stack_trace_posix.cc | |
| parent | 164f7496de0fbee436b385a79ead9e3cb81a50c1 (diff) | |
| download | external_chromium-513209b27ff55e2841eac0e4120199c23acce758.zip external_chromium-513209b27ff55e2841eac0e4120199c23acce758.tar.gz external_chromium-513209b27ff55e2841eac0e4120199c23acce758.tar.bz2 | |
Merge Chromium at r65505: Initial merge by git.
Change-Id: I31d8f1d8cd33caaf7f47ffa7350aef42d5fbdb45
Diffstat (limited to 'base/debug/stack_trace_posix.cc')
| -rw-r--r-- | base/debug/stack_trace_posix.cc | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc new file mode 100644 index 0000000..e4b0ef2 --- /dev/null +++ b/base/debug/stack_trace_posix.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/debug/stack_trace.h" + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <unistd.h> + +#include <string> +#include <vector> + +#if defined(__GLIBCXX__) +#include <cxxabi.h> +#endif + +#if defined(OS_MACOSX) +#include <AvailabilityMacros.h> +#endif + +#include <iostream> + +#include "base/basictypes.h" +#include "base/compat_execinfo.h" +#include "base/eintr_wrapper.h" +#include "base/logging.h" +#include "base/safe_strerror_posix.h" +#include "base/scoped_ptr.h" +#include "base/string_piece.h" +#include "base/stringprintf.h" + +#if defined(USE_SYMBOLIZE) +#include "base/third_party/symbolize/symbolize.h" +#endif + +namespace base { +namespace debug { + +namespace { + +// The prefix used for mangled symbols, per the Itanium C++ ABI: +// http://www.codesourcery.com/cxx-abi/abi.html#mangling +const char kMangledSymbolPrefix[] = "_Z"; + +// Characters that can be used for symbols, generated by Ruby: +// (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join +const char kSymbolCharacters[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; + +#if !defined(USE_SYMBOLIZE) +// Demangles C++ symbols in the given text. Example: +// +// "sconsbuild/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]" +// => +// "sconsbuild/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]" +void DemangleSymbols(std::string* text) { +#if defined(__GLIBCXX__) + + std::string::size_type search_from = 0; + while (search_from < text->size()) { + // Look for the start of a mangled symbol, from search_from. + std::string::size_type mangled_start = + text->find(kMangledSymbolPrefix, search_from); + if (mangled_start == std::string::npos) { + break; // Mangled symbol not found. + } + + // Look for the end of the mangled symbol. + std::string::size_type mangled_end = + text->find_first_not_of(kSymbolCharacters, mangled_start); + if (mangled_end == std::string::npos) { + mangled_end = text->size(); + } + std::string mangled_symbol = + text->substr(mangled_start, mangled_end - mangled_start); + + // Try to demangle the mangled symbol candidate. + int status = 0; + scoped_ptr_malloc<char> demangled_symbol( + abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status)); + if (status == 0) { // Demangling is successful. + // Remove the mangled symbol. + text->erase(mangled_start, mangled_end - mangled_start); + // Insert the demangled symbol. + text->insert(mangled_start, demangled_symbol.get()); + // Next time, we'll start right after the demangled symbol we inserted. + search_from = mangled_start + strlen(demangled_symbol.get()); + } else { + // Failed to demangle. Retry after the "_Z" we just found. + search_from = mangled_start + 2; + } + } + +#endif // defined(__GLIBCXX__) +} +#endif // !defined(USE_SYMBOLIZE) + +// Gets the backtrace as a vector of strings. If possible, resolve symbol +// names and attach these. Otherwise just use raw addresses. Returns true +// if any symbol name is resolved. Returns false on error and *may* fill +// in |error_message| if an error message is available. +bool GetBacktraceStrings(void **trace, int size, + std::vector<std::string>* trace_strings, + std::string* error_message) { + bool symbolized = false; + +#if defined(USE_SYMBOLIZE) + for (int i = 0; i < size; ++i) { + char symbol[1024]; + // Subtract by one as return address of function may be in the next + // function when a function is annotated as noreturn. + if (google::Symbolize(static_cast<char *>(trace[i]) - 1, + symbol, sizeof(symbol))) { + // Don't call DemangleSymbols() here as the symbol is demangled by + // google::Symbolize(). + trace_strings->push_back( + base::StringPrintf("%s [%p]", symbol, trace[i])); + symbolized = true; + } else { + trace_strings->push_back(base::StringPrintf("%p", trace[i])); + } + } +#else + scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace, size)); + if (trace_symbols.get()) { + for (int i = 0; i < size; ++i) { + std::string trace_symbol = trace_symbols.get()[i]; + DemangleSymbols(&trace_symbol); + trace_strings->push_back(trace_symbol); + } + symbolized = true; + } else { + if (error_message) + *error_message = safe_strerror(errno); + for (int i = 0; i < size; ++i) { + trace_strings->push_back(base::StringPrintf("%p", trace[i])); + } + } +#endif // defined(USE_SYMBOLIZE) + + return symbolized; +} + +} // namespace + +StackTrace::StackTrace() { +#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + if (backtrace == NULL) { + count_ = 0; + return; + } +#endif + // Though the backtrace API man page does not list any possible negative + // return values, we take no chance. + count_ = std::max(backtrace(trace_, arraysize(trace_)), 0); +} + +void StackTrace::PrintBacktrace() { +#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + if (backtrace_symbols_fd == NULL) + return; +#endif + fflush(stderr); + std::vector<std::string> trace_strings; + GetBacktraceStrings(trace_, count_, &trace_strings, NULL); + for (size_t i = 0; i < trace_strings.size(); ++i) { + std::cerr << "\t" << trace_strings[i] << "\n"; + } +} + +void StackTrace::OutputToStream(std::ostream* os) { +#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + if (backtrace_symbols == NULL) + return; +#endif + std::vector<std::string> trace_strings; + std::string error_message; + if (GetBacktraceStrings(trace_, count_, &trace_strings, &error_message)) { + (*os) << "Backtrace:\n"; + } else { + if (!error_message.empty()) + error_message = " (" + error_message + ")"; + (*os) << "Unable to get symbols for backtrace" << error_message << ". " + << "Dumping raw addresses in trace:\n"; + } + + for (size_t i = 0; i < trace_strings.size(); ++i) { + (*os) << "\t" << trace_strings[i] << "\n"; + } +} + +} // namespace debug +} // namespace base |
