Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
stacktrace.cc
Go to the documentation of this file.
1 
18 #include "ion/port/stacktrace.h"
19 
20 #if defined(ION_PLATFORM_LINUX) || defined(ION_PLATFORM_MAC) || \
21  defined(ION_PLATFORM_IOS)
22 # define ION_STACKTRACE_POSIX
23 # include <execinfo.h>
24 # include <cstdlib>
25 #elif defined(ION_PLATFORM_WINDOWS)
26 # if !ION_PRODUCTION
27 # include <assert.h> // For checking return values (port has no logging).
28 # include <windows.h>
29 # include <WinBase.h>
30 # include <DbgHelp.h>
31 # include <iomanip>
32 # pragma comment(lib, "dbghelp") // Add library in non-production build
33 # pragma comment(lib, "psapi") // Add library in non-production build
34 # endif
35 #endif
36 
37 #include <sstream>
38 
39 namespace ion {
40 namespace port {
41 
43 #if !ION_PRODUCTION
44 #if defined(ION_STACKTRACE_POSIX)
45  const int kMaxStackTraceDepth = 128; // Arbitrary limit.
47  addresses_.resize(kMaxStackTraceDepth);
48  const int depth = backtrace(&addresses_[0], kMaxStackTraceDepth);
49  addresses_.resize(depth);
50 
51 #elif defined(ION_PLATFORM_WINDOWS)
52  const int kMaxStackTraceDepth = 62; // < 63 according to Windows API.
54  addresses_.resize(kMaxStackTraceDepth);
55  const int depth =
56  CaptureStackBackTrace(0, kMaxStackTraceDepth, &addresses_[0], NULL);
57  assert(depth > 0);
58  addresses_.resize(depth);
59 
60 #else
61 
63 
64 #endif
65 #endif
66 }
67 
68 void StackTrace::ObtainSymbols() const {
69 #if !ION_PRODUCTION
70 #if defined(ION_STACKTRACE_POSIX)
71  char** trace_cstrings =
73  backtrace_symbols(&addresses_[0], static_cast<int>(addresses_.size()));
74  for (size_t i = 0; i < addresses_.size(); ++i) {
75  symbols_.push_back(std::string(trace_cstrings[i]));
76  }
77  free(trace_cstrings);
78 
79 #elif defined(ION_PLATFORM_WINDOWS)
80  const int kMaxNameLength = 255;
82  const int kSymbolSize =
83  sizeof(SYMBOL_INFO) + (kMaxNameLength * sizeof(TCHAR));
84  char symbol_memory[kSymbolSize] = {0};
85  SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(symbol_memory);
86  symbol->MaxNameLen = kMaxNameLength;
87  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
88 
89  const HANDLE process = GetCurrentProcess();
90  SymInitialize(process, NULL, TRUE);
91  for (size_t i = 0; i < addresses_.size(); ++i) {
92  const DWORD64 address = reinterpret_cast<DWORD64>(addresses_[i]);
93  const BOOL success = SymFromAddr(process, address, 0, symbol);
94  std::ostringstream output;
95  if (success == TRUE) {
96  output << symbol->Name;
97  } else {
98  output << "??? [0x" << std::hex << address << "]"
99  << "symbol not found; GetLastError() returns " << GetLastError();
100  }
101  symbols_.push_back(output.str());
102  }
103  SymCleanup(process);
104 
105 #else
106 
108 
109 #endif
110 #endif
111 }
112 
113 #undef ION_STACKTRACE_POSIX
114 
115 const std::vector<std::string>& StackTrace::GetSymbols() const {
116  if (symbols_.empty())
117  ObtainSymbols();
118  return symbols_;
119 }
120 
121 const std::string StackTrace::GetSymbolString() const {
122  const std::vector<void*>& addresses = GetAddresses();
123  const std::vector<std::string>& symbols = GetSymbols();
124  std::ostringstream output;
125  for (size_t i = 0; i < addresses.size(); ++i) {
126  output << "[" << addresses[i] << "]: " << symbols[i] << std::endl;
127  }
128  return output.str();
129 }
130 
131 } // namespace port
132 } // namespace ion
const std::vector< void * > & GetAddresses() const
Returns the stack as a vector of addresses.
Definition: stacktrace.h:38
const std::vector< std::string > & GetSymbols() const
Returns the stack as a vector of symbol names.
Definition: stacktrace.cc:115
const std::string GetSymbolString() const
Returns formatted string containing symbolic function names for elements of the stack trace...
Definition: stacktrace.cc:121