1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 #include <fc_config.h>
16 #endif /* HAVE_CONFIG_H */
18 #include "fc_prehdrs.h"
20 #ifdef HAVE_EXECINFO_H
28 #include "fcbacktrace.h"
30 /* We don't want backtrace-spam to testmatic logs */
31 #if defined(FREECIV_DEBUG) && defined(HAVE_BACKTRACE) && !defined(FREECIV_TESTMATIC)
32 #define BACKTRACE_ACTIVE 1
35 #ifdef BACKTRACE_ACTIVE
37 /* We write always in level LOG_NORMAL and not in higher one since those
38 * interact badly with server callback to send error messages to local
40 #define LOG_BACKTRACE LOG_NORMAL
42 #define MAX_NUM_FRAMES 64
44 static log_pre_callback_fn previous
= NULL
;
46 static void write_backtrace_line(enum log_level level
, bool print_from_where
,
47 const char *where
, const char *msg
);
48 static void backtrace_log(enum log_level level
, bool print_from_where
,
49 const char *where
, const char *msg
);
50 #endif /* BACKTRACE_ACTIVE */
52 /************************************************************************
53 Take backtrace log callback to use
54 ************************************************************************/
55 void backtrace_init(void)
57 #ifdef BACKTRACE_ACTIVE
58 previous
= log_set_pre_callback(backtrace_log
);
62 /************************************************************************
63 Remove backtrace log callback from use
64 ************************************************************************/
65 void backtrace_deinit(void)
67 #ifdef BACKTRACE_ACTIVE
68 log_pre_callback_fn active
;
70 active
= log_set_pre_callback(previous
);
72 if (active
!= backtrace_log
) {
73 /* We were not the active callback!
74 * Restore the active callback and log error */
75 log_set_pre_callback(active
);
76 log_error("Backtrace log (pre)callback cannot be removed");
78 #endif /* BACKTRACE_ACTIVE */
81 #ifdef BACKTRACE_ACTIVE
82 /************************************************************************
83 Write one line of backtrace
84 ************************************************************************/
85 static void write_backtrace_line(enum log_level level
, bool print_from_where
,
86 const char *where
, const char *msg
)
88 /* Current behavior of this function is to write to chained callback,
89 * nothing more, nothing less. */
90 if (previous
!= NULL
) {
91 previous(level
, print_from_where
, where
, msg
);
95 /*****************************************************************************
96 Main backtrace callback called from logging code.
97 *****************************************************************************/
98 static void backtrace_log(enum log_level level
, bool print_from_where
,
99 const char *where
, const char *msg
)
101 if (previous
!= NULL
) {
102 /* Call chained callback first */
103 previous(level
, print_from_where
, where
, msg
);
106 if (level
<= LOG_ERROR
) {
107 backtrace_print(LOG_BACKTRACE
);
111 #endif /* BACKTRACE_ACTIVE */
113 /*****************************************************************************
115 *****************************************************************************/
116 void backtrace_print(enum log_level level
)
118 #ifdef BACKTRACE_ACTIVE
119 void *buffer
[MAX_NUM_FRAMES
];
123 frames
= backtrace(buffer
, ARRAY_SIZE(buffer
));
124 names
= backtrace_symbols(buffer
, frames
);
127 write_backtrace_line(level
, FALSE
, NULL
, "No backtrace");
131 write_backtrace_line(level
, FALSE
, NULL
, "Backtrace:");
133 for (i
= 0; i
< MIN(frames
, MAX_NUM_FRAMES
); i
++) {
136 fc_snprintf(linestr
, sizeof(linestr
), "%5d: %s", i
, names
[i
]);
138 write_backtrace_line(level
, FALSE
, NULL
, linestr
);
143 #endif /* BACKTRACE_ACTIVE */