stack_trace_posix.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/debug/stack_trace.h" 6 7#include <errno.h> 8#include <fcntl.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <sys/stat.h> 12#include <sys/sysctl.h> 13#include <sys/types.h> 14#include <unistd.h> 15 16#include <string> 17#include <vector> 18 19#if defined(__GLIBCXX__) 20#include <cxxabi.h> 21#endif 22 23#if defined(OS_MACOSX) 24#include <AvailabilityMacros.h> 25#endif 26 27#include <iostream> 28 29#include "base/basictypes.h" 30#include "base/compat_execinfo.h" 31#include "base/eintr_wrapper.h" 32#include "base/logging.h" 33#include "base/safe_strerror_posix.h" 34#include "base/scoped_ptr.h" 35#include "base/string_piece.h" 36#include "base/stringprintf.h" 37 38#if defined(USE_SYMBOLIZE) 39#include "base/third_party/symbolize/symbolize.h" 40#endif 41 42namespace base { 43namespace debug { 44 45namespace { 46 47// The prefix used for mangled symbols, per the Itanium C++ ABI: 48// http://www.codesourcery.com/cxx-abi/abi.html#mangling 49const char kMangledSymbolPrefix[] = "_Z"; 50 51// Characters that can be used for symbols, generated by Ruby: 52// (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join 53const char kSymbolCharacters[] = 54 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; 55 56#if !defined(USE_SYMBOLIZE) 57// Demangles C++ symbols in the given text. Example: 58// 59// "sconsbuild/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]" 60// => 61// "sconsbuild/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]" 62void DemangleSymbols(std::string* text) { 63#if defined(__GLIBCXX__) 64 65 std::string::size_type search_from = 0; 66 while (search_from < text->size()) { 67 // Look for the start of a mangled symbol, from search_from. 68 std::string::size_type mangled_start = 69 text->find(kMangledSymbolPrefix, search_from); 70 if (mangled_start == std::string::npos) { 71 break; // Mangled symbol not found. 72 } 73 74 // Look for the end of the mangled symbol. 75 std::string::size_type mangled_end = 76 text->find_first_not_of(kSymbolCharacters, mangled_start); 77 if (mangled_end == std::string::npos) { 78 mangled_end = text->size(); 79 } 80 std::string mangled_symbol = 81 text->substr(mangled_start, mangled_end - mangled_start); 82 83 // Try to demangle the mangled symbol candidate. 84 int status = 0; 85 scoped_ptr_malloc<char> demangled_symbol( 86 abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status)); 87 if (status == 0) { // Demangling is successful. 88 // Remove the mangled symbol. 89 text->erase(mangled_start, mangled_end - mangled_start); 90 // Insert the demangled symbol. 91 text->insert(mangled_start, demangled_symbol.get()); 92 // Next time, we'll start right after the demangled symbol we inserted. 93 search_from = mangled_start + strlen(demangled_symbol.get()); 94 } else { 95 // Failed to demangle. Retry after the "_Z" we just found. 96 search_from = mangled_start + 2; 97 } 98 } 99 100#endif // defined(__GLIBCXX__) 101} 102#endif // !defined(USE_SYMBOLIZE) 103 104// Gets the backtrace as a vector of strings. If possible, resolve symbol 105// names and attach these. Otherwise just use raw addresses. Returns true 106// if any symbol name is resolved. Returns false on error and *may* fill 107// in |error_message| if an error message is available. 108bool GetBacktraceStrings(void **trace, int size, 109 std::vector<std::string>* trace_strings, 110 std::string* error_message) { 111 bool symbolized = false; 112 113#if defined(USE_SYMBOLIZE) 114 for (int i = 0; i < size; ++i) { 115 char symbol[1024]; 116 // Subtract by one as return address of function may be in the next 117 // function when a function is annotated as noreturn. 118 if (google::Symbolize(static_cast<char *>(trace[i]) - 1, 119 symbol, sizeof(symbol))) { 120 // Don't call DemangleSymbols() here as the symbol is demangled by 121 // google::Symbolize(). 122 trace_strings->push_back( 123 base::StringPrintf("%s [%p]", symbol, trace[i])); 124 symbolized = true; 125 } else { 126 trace_strings->push_back(base::StringPrintf("%p", trace[i])); 127 } 128 } 129#else 130 scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace, size)); 131 if (trace_symbols.get()) { 132 for (int i = 0; i < size; ++i) { 133 std::string trace_symbol = trace_symbols.get()[i]; 134 DemangleSymbols(&trace_symbol); 135 trace_strings->push_back(trace_symbol); 136 } 137 symbolized = true; 138 } else { 139 if (error_message) 140 *error_message = safe_strerror(errno); 141 for (int i = 0; i < size; ++i) { 142 trace_strings->push_back(base::StringPrintf("%p", trace[i])); 143 } 144 } 145#endif // defined(USE_SYMBOLIZE) 146 147 return symbolized; 148} 149 150} // namespace 151 152StackTrace::StackTrace() { 153#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 154 if (backtrace == NULL) { 155 count_ = 0; 156 return; 157 } 158#endif 159 // Though the backtrace API man page does not list any possible negative 160 // return values, we take no chance. 161 count_ = std::max(backtrace(trace_, arraysize(trace_)), 0); 162} 163 164void StackTrace::PrintBacktrace() { 165#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 166 if (backtrace_symbols_fd == NULL) 167 return; 168#endif 169 fflush(stderr); 170 std::vector<std::string> trace_strings; 171 GetBacktraceStrings(trace_, count_, &trace_strings, NULL); 172 for (size_t i = 0; i < trace_strings.size(); ++i) { 173 std::cerr << "\t" << trace_strings[i] << "\n"; 174 } 175} 176 177void StackTrace::OutputToStream(std::ostream* os) { 178#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 179 if (backtrace_symbols == NULL) 180 return; 181#endif 182 std::vector<std::string> trace_strings; 183 std::string error_message; 184 if (GetBacktraceStrings(trace_, count_, &trace_strings, &error_message)) { 185 (*os) << "Backtrace:\n"; 186 } else { 187 if (!error_message.empty()) 188 error_message = " (" + error_message + ")"; 189 (*os) << "Unable to get symbols for backtrace" << error_message << ". " 190 << "Dumping raw addresses in trace:\n"; 191 } 192 193 for (size_t i = 0; i < trace_strings.size(); ++i) { 194 (*os) << "\t" << trace_strings[i] << "\n"; 195 } 196} 197 198} // namespace debug 199} // namespace base 200