Freeciv21
Develop your civilization from humble roots to a global empire
fcbacktrace.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include <QLoggingCategory>
15 #include <sstream>
16 
17 #ifdef FREECIV_DEBUG
18 #include <backward.hpp>
19 #endif
20 
21 // utility
22 #include "log.h"
23 
24 #include "fcbacktrace.h"
25 
26 // We don't want backtrace-spam to testmatic logs
27 #if defined(FREECIV_DEBUG) && !defined(FREECIV_TESTMATIC)
28 #define BACKTRACE_ACTIVE 1
29 #endif
30 
31 #ifdef BACKTRACE_ACTIVE
32 #define MAX_NUM_FRAMES 64
33 
34 Q_LOGGING_CATEGORY(stack_category, "freeciv.stacktrace")
35 
36 namespace {
37 static QtMessageHandler previous = nullptr;
38 
39 static void backtrace_log(QtMsgType type, const QMessageLogContext &context,
40  const QString &message);
41 void backtrace_print(QtMsgType type, const QMessageLogContext &context);
42 } // anonymous namespace
43 #endif // BACKTRACE_ACTIVE
44 
49 {
50 #ifdef BACKTRACE_ACTIVE
51  previous = qInstallMessageHandler(backtrace_log);
52 #endif
53 }
54 
59 {
60 #ifdef BACKTRACE_ACTIVE
61  qInstallMessageHandler(previous);
62 #endif // BACKTRACE_ACTIVE
63 }
64 
65 #ifdef BACKTRACE_ACTIVE
69 namespace {
70 static void backtrace_log(QtMsgType type, const QMessageLogContext &context,
71  const QString &message)
72 {
73  if (type == QtFatalMsg || type == QtCriticalMsg) {
74  backtrace_print(type, context);
75  }
76 
77  if (previous != nullptr) {
78  // Call chained callback after printing the trace, because it might
79  // abort()
80  previous(type, context, message);
81  }
82 }
83 } // anonymous namespace
84 
85 namespace {
89 void backtrace_print(QtMsgType type, const QMessageLogContext &context)
90 {
91  if (!stack_category().isEnabled(QtDebugMsg)) {
92  // We won't print anything anyway. Since walking the stack is
93  // expensive, return immediately.
94  return;
95  }
96 
97  using namespace backward;
98  StackTrace st;
99  st.load_here(MAX_NUM_FRAMES);
100 
101  // Generate the trace string
102  Printer p;
103  p.object = false;
104  p.address = true;
105 
106  std::stringstream ss;
107  p.print(st, ss);
108 
109  // Create a new context with the correct category name.
110  QMessageLogContext modified_context(context.file, context.line,
111  context.function,
112  stack_category().categoryName());
113 
114  // Print
115  std::string line;
116  while (std::getline(ss, line)) {
117  // Do the formatting manually (this is called from the message handler
118  // and automatic formatting doesn't appear to work there).
119  qCDebug(stack_category).noquote()
120  << qFormatLogMessage(type, modified_context, line.data());
121  }
122 }
123 
124 } // anonymous namespace
125 #endif // BACKTRACE_ACTIVE
void backtrace_init()
Take backtrace log callback to use.
Definition: fcbacktrace.cpp:48
void backtrace_deinit()
Remove backtrace log callback from use.
Definition: fcbacktrace.cpp:58
Q_LOGGING_CATEGORY(tileset_category, "freeciv.tileset")
Functions for handling the tilespec files which describe the files and contents of tilesets.