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