1 /******************************************************************************
3 * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #include "base/stacktrace.hpp"
21 #include "base/utility.hpp"
22 #include "base/initialize.hpp"
24 #ifdef HAVE_BACKTRACE_SYMBOLS
25 # include <execinfo.h>
26 #endif /* HAVE_BACKTRACE_SYMBOLS */
28 using namespace icinga;
30 INITIALIZE_ONCE(&StackTrace::StaticInitialize);
33 # pragma optimize("", off)
36 StackTrace::StackTrace(void)
38 #ifdef HAVE_BACKTRACE_SYMBOLS
39 m_Count = backtrace(m_Frames, sizeof(m_Frames) / sizeof(m_Frames[0]));
40 #else /* HAVE_BACKTRACE_SYMBOLS */
42 m_Count = CaptureStackBackTrace(0, sizeof(m_Frames) / sizeof(m_Frames), m_Frames, NULL);
46 #endif /* HAVE_BACKTRACE_SYMBOLS */
50 # pragma optimize("", on)
54 StackTrace::StackTrace(PEXCEPTION_POINTERS exi)
60 architecture = IMAGE_FILE_MACHINE_AMD64;
62 frame.AddrPC.Offset = exi->ContextRecord->Rip;
63 frame.AddrFrame.Offset = exi->ContextRecord->Rbp;
64 frame.AddrStack.Offset = exi->ContextRecord->Rsp;
66 architecture = IMAGE_FILE_MACHINE_I386;
68 frame.AddrPC.Offset = exi->ContextRecord->Eip;
69 frame.AddrFrame.Offset = exi->ContextRecord->Ebp;
70 frame.AddrStack.Offset = exi->ContextRecord->Esp;
73 frame.AddrPC.Mode = AddrModeFlat;
74 frame.AddrFrame.Mode = AddrModeFlat;
75 frame.AddrStack.Mode = AddrModeFlat;
79 while (StackWalk64(architecture, GetCurrentProcess(), GetCurrentThread(),
80 &frame, exi->ContextRecord, NULL, &SymFunctionTableAccess64,
81 &SymGetModuleBase64, NULL) && m_Count < sizeof(m_Frames) / sizeof(m_Frames[0])) {
82 m_Frames[m_Count] = reinterpret_cast<void *>(frame.AddrPC.Offset);
88 void StackTrace::StaticInitialize(void)
91 (void) SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
92 (void) SymInitialize(GetCurrentProcess(), NULL, TRUE);
97 * Prints a stacktrace to the specified stream.
99 * @param fp The stream.
100 * @param ignoreFrames The number of stackframes to ignore (in addition to
101 * the one this function is executing in).
102 * @returns true if the stacktrace was printed, false otherwise.
104 void StackTrace::Print(std::ostream& fp, int ignoreFrames) const
109 # ifdef HAVE_BACKTRACE_SYMBOLS
110 char **messages = backtrace_symbols(m_Frames, m_Count);
112 for (int i = ignoreFrames + 1; i < m_Count && messages != NULL; ++i) {
113 String message = messages[i];
115 char *sym_begin = strchr(messages[i], '(');
118 char *sym_end = strchr(sym_begin, '+');
120 if (sym_end != NULL) {
121 String sym = String(sym_begin + 1, sym_end);
122 String sym_demangled = Utility::DemangleSymbolName(sym);
124 if (sym_demangled.IsEmpty())
125 sym_demangled = "<unknown function>";
127 String path = String(messages[i], sym_begin);
129 size_t slashp = path.RFind("/");
131 if (slashp != String::NPos)
132 path = path.SubStr(slashp + 1);
134 message = path + ": " + sym_demangled + " (" + String(sym_end);
138 fp << "\t(" << i - ignoreFrames - 1 << ") " << message << std::endl;
144 # else /* HAVE_BACKTRACE_SYMBOLS */
145 fp << "(not available)" << std::endl;
146 # endif /* HAVE_BACKTRACE_SYMBOLS */
148 for (int i = ignoreFrames + 1; i < m_Count; i++) {
149 fp << "\t(" << i - ignoreFrames - 1 << "): "
150 << Utility::GetSymbolName(m_Frames[i])
156 std::ostream& icinga::operator<<(std::ostream& stream, const StackTrace& trace)
158 trace.Print(stream, 1);