The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
debug.h
Go to the documentation of this file.
1#pragma once
2/*
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 of the License, or
6 * (at your option) any later version.
7 *
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 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/** Debugging function definitions and structures
19 *
20 * @file src/lib/util/debug.h
21 *
22 * @copyright 2015-2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24#ifdef __cplusplus
25extern "C" {
26#endif
27
28#include <freeradius-devel/build.h>
29#include <freeradius-devel/missing.h>
30#include <freeradius-devel/util/talloc.h>
31
32#include <signal.h>
33
34#ifdef NO_ASSERT
35# define MEM(x) error "Use of MEM() not allowed in this source file. Deal with memory allocation failure gracefully"
36#else
37/* Short circuit condition to prevent duplicate evaluation */
38# define MEM(x) do { if (!(x)) { fr_cond_assert_msg(0 && (x), "OUT OF MEMORY"); _fr_exit(__FILE__, __LINE__, EXIT_FAILURE, true); } } while (0)
39#endif
40
41typedef enum {
42 DEBUGGER_STATE_UNKNOWN_NO_PTRACE = -3, //!< We don't have ptrace so can't check.
43 DEBUGGER_STATE_UNKNOWN_NO_PTRACE_CAP = -2, //!< CAP_SYS_PTRACE not set for the process.
44 DEBUGGER_STATE_UNKNOWN = -1, //!< Unknown, likely fr_get_debug_state() not called yet.
45 DEBUGGER_STATE_NOT_ATTACHED = 0, //!< We can attach, so a debugger must not be.
46 DEBUGGER_STATE_ATTACHED = 1 //!< We can't attach, it's likely a debugger is already tracing.
48
49extern int fr_fault_log_fd;
51
52#define FR_FAULT_LOG(_fmt, ...) fr_fault_log(_fmt "\n", ## __VA_ARGS__)
53#define FR_FAULT_LOG_HEX(_data, _data_len) fr_fault_log_hex(_data, _data_len)
54
55/** Optional callback passed to fr_fault_setup
56 *
57 * Allows optional logic to be run before calling the main fault handler.
58 *
59 * If the callback returns < 0, the main fault handler will not be called.
60 *
61 * @param signum signal raised.
62 * @return
63 * - 0 on success.
64 * - < 0 on failure.
65 */
66typedef int (*fr_fault_cb_t)(int signum);
67
68int fr_get_lsan_state(void);
69
70int fr_get_debug_state(void);
71
72void fr_debug_state_store(void);
73
75
76void fr_debug_break(bool always);
77
78void fr_panic_on_free(TALLOC_CTX *ctx);
79
80int fr_set_dumpable_init(void);
81
82int fr_set_dumpable(bool allow_core_dumps);
83
84int fr_reset_dumpable(void);
85
86int fr_log_talloc_report(TALLOC_CTX const *ctx);
87
88void fr_fault(int sig);
89
90void fr_talloc_fault_setup(void);
91
92void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx);
93
94/** Bitmask of signal numbers to install the panic-action handler on.
95 *
96 * PANIC_ACTION_SIGNALS is the default set installed by every FreeRADIUS
97 * program. Callers that share a signal with another library (e.g. libFuzzer
98 * also uses SIGALRM for its own timeout) pass PANIC_ACTION_SIGNALS with the
99 * offending bit cleared so the FR handler is not registered for that signal
100 * and the other library's handler stays in place.
101 */
102#ifdef SIGABRT
103# define _PANIC_ACTION_SIGABRT (1UL << SIGABRT)
104#else
105# define _PANIC_ACTION_SIGABRT 0
106#endif
107#ifdef SIGILL
108# define _PANIC_ACTION_SIGILL (1UL << SIGILL)
109#else
110# define _PANIC_ACTION_SIGILL 0
111#endif
112#ifdef SIGFPE
113# define _PANIC_ACTION_SIGFPE (1UL << SIGFPE)
114#else
115# define _PANIC_ACTION_SIGFPE 0
116#endif
117#ifdef SIGSEGV
118# define _PANIC_ACTION_SIGSEGV (1UL << SIGSEGV)
119#else
120# define _PANIC_ACTION_SIGSEGV 0
121#endif
122#ifdef SIGALRM
123# define _PANIC_ACTION_SIGALRM (1UL << SIGALRM)
124#else
125# define _PANIC_ACTION_SIGALRM 0
126#endif
127
128#define PANIC_ACTION_SIGNALS (_PANIC_ACTION_SIGABRT | _PANIC_ACTION_SIGILL | \
129 _PANIC_ACTION_SIGFPE | _PANIC_ACTION_SIGSEGV | \
130 _PANIC_ACTION_SIGALRM)
131
132int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program,
133 unsigned long fault_signals);
134
136
137void fr_fault_set_log_fd(int fd);
138
139void fr_fault_log(char const *msg, ...) CC_HINT(format (printf, 1, 2));
140
141void fr_fault_log_hex(uint8_t const *data, size_t data_len);
142
143/** @name Assertion support functions
144 * @{
145 */
146bool _fr_assert_fail(char const *file, int line, char const *expr, char const *msg, ...)
147 CC_HINT(format (printf, 4, 5));
148
149NEVER_RETURNS void _fr_assert_fatal(char const *file, int line, char const *expr, char const *msg, ...)
150 CC_HINT(format (printf, 4, 5));
151
152NEVER_RETURNS void _fr_exit(char const *file, int line, int status, bool now);
153/** @} */
154
155/** @name Assertion and exit macros
156 * @{
157 */
158
159/** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x
160 *
161 * Should be wrapped in a condition, and if false, should cause function to return
162 * an error code. This allows control to return to the caller if a precondition is
163 * not satisfied and we're not debugging.
164 *
165 * Example:
166 @verbatim
167 if (!fr_cond_assert(request)) return -1
168 @endverbatim
169 *
170 * @param[in] _x expression to test (should evaluate to true)
171 */
172#define fr_cond_assert(_x) likely((bool)((_x) ? true : (_fr_assert_fail(__FILE__, __LINE__, #_x, NULL) && false)))
173
174/** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x
175 *
176 * Should be wrapped in a condition, and if false, should cause function to return
177 * an error code. This allows control to return to the caller if a precondition is
178 * not satisfied and we're not debugging.
179 *
180 * Example:
181 @verbatim
182 if (!fr_cond_assert_msg(request, "Bad stuff happened: %s", fr_syserror(errno)))) return -1
183 @endverbatim
184 *
185 * @param[in] _x expression to test (should evaluate to true)
186 * @param[in] _fmt of message to log.
187 * @param[in] ... fmt arguments.
188 */
189#define fr_cond_assert_msg(_x, _fmt, ...) likely((bool)((_x) ? true : (_fr_assert_fail(__FILE__, __LINE__, #_x, _fmt, ## __VA_ARGS__) && false)))
190
191/** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
192 *
193 * Example:
194 @verbatim
195 fr_fatal_assert(<extremely_unlikely_and_fatal_condition>);
196 @endverbatim
197 *
198 * @param _x expression to test (should evaluate to true)
199 */
200#define fr_fatal_assert(_x) if (unlikely(!((bool)(_x)))) _fr_assert_fatal(__FILE__, __LINE__, #_x, NULL)
201
202/** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
203 *
204 * Should be wrapped in a condition, and if false, should cause function to return
205 * an error code. This allows control to return to the caller if a precondition is
206 * not satisfied and we're not debugging.
207 *
208 * Example:
209 @verbatim
210 fr_fatal_assert(<extremely_unlikely_and_fatal_condition>);
211 @endverbatim
212 *
213 * @param[in] _x expression to test (should evaluate to true)
214 * @param[in] _fmt of message to log.
215 * @param[in] ... fmt arguments.
216 */
217#define fr_fatal_assert_msg(_x, _fmt, ...) if (unlikely(!((bool)(_x)))) _fr_assert_fatal(__FILE__, __LINE__, #_x, _fmt, ## __VA_ARGS__)
218
219/** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
220 *
221 * @param[in] _msg to log.
222 * @param[in] ... args.
223 */
224#define fr_fatal_assert_fail(_msg, ...) _fr_assert_fatal(__FILE__, __LINE__, "false", _msg, ## __VA_ARGS__)
225
226#ifdef NDEBUG
227# define fr_assert(_x)
228# define fr_assert_msg(_x, _msg, ...)
229# define fr_assert_fail(_msg, ...)
230#elif !defined(STATIC_ANALYZER)
231/** Calls panic_action ifndef NDEBUG, else logs error
232 *
233 * @param[in] _x expression to test (should evaluate to true)
234 */
235# define fr_assert(_x) if (unlikely(!((bool)(_x)))) _fr_assert_fail(__FILE__, __LINE__, #_x, NULL)
236
237/** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
238 *
239 * @param[in] _x expression to test (should evaluate to true)
240 * @param[in] _msg to log.
241 * @param[in] ... args.
242 */
243# define fr_assert_msg(_x, _msg, ...) if (unlikely(!((bool)(_x)))) _fr_assert_fail(__FILE__, __LINE__, #_x, _msg, ## __VA_ARGS__)
244/** Calls panic_action ifndef NDEBUG, else logs error
245 *
246 * @param[in] _msg to log.
247 * @param[in] ... args.
248 */
249#define fr_assert_fail(_msg, ...) _fr_assert_fail(__FILE__, __LINE__, "false", _msg, ## __VA_ARGS__)
250#else
251# include <assert.h>
252# define fr_assert(_x) assert(_x)
253# define fr_assert_msg(_x, _msg, ...) assert(_x)
254# define fr_assert_fail(_msg, ...) assert(0)
255#endif
256
257/** Exit, producing a log message in debug builds
258 *
259 * @param[in] _x code to exit with.
260 */
261# define fr_exit(_x) _fr_exit(__FILE__, __LINE__, (_x), false)
262
263/** Exit without calling atexit() handlers, producing a log message in debug builds
264 *
265 * @param[in] _x code to exit with.
266 */
267# define fr_exit_now(_x) _fr_exit(__FILE__, __LINE__, (_x), true)
268/** @} */
269
270#ifdef __cplusplus
271}
272#endif
log_entry msg
Definition acutest.h:794
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:382
char const * fr_debug_state_to_msg(fr_debug_state_t state)
Return current value of debug_state.
Definition debug.c:525
bool _fr_assert_fail(char const *file, int line, char const *expr, char const *msg,...))
A soft assertion which triggers the fault handler in debug builds.
Definition debug.c:1272
fr_debug_state_t
Definition debug.h:41
@ DEBUGGER_STATE_NOT_ATTACHED
We can attach, so a debugger must not be.
Definition debug.h:45
@ DEBUGGER_STATE_UNKNOWN_NO_PTRACE
We don't have ptrace so can't check.
Definition debug.h:42
@ DEBUGGER_STATE_UNKNOWN_NO_PTRACE_CAP
CAP_SYS_PTRACE not set for the process.
Definition debug.h:43
@ DEBUGGER_STATE_UNKNOWN
Unknown, likely fr_get_debug_state() not called yet.
Definition debug.h:44
@ DEBUGGER_STATE_ATTACHED
We can't attach, it's likely a debugger is already tracing.
Definition debug.h:46
void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx)
Disable the null tracking context when a talloc chunk is freed.
Definition debug.c:1034
void fr_fault_set_log_fd(int fd)
Set a file descriptor to log memory reports to.
Definition debug.c:1258
int fr_log_talloc_report(TALLOC_CTX const *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
Definition debug.c:975
int fr_set_dumpable(bool allow_core_dumps)
Enable or disable core dumps.
Definition debug.c:688
void fr_fault_log(char const *msg,...))
Log output to the fr_fault_log_fd.
Definition debug.c:1224
int fr_fault_log_fd
Where to write debug output.
Definition debug.c:72
int(* fr_fault_cb_t)(int signum)
Optional callback passed to fr_fault_setup.
Definition debug.h:66
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
Definition debug.c:756
NEVER_RETURNS void _fr_assert_fatal(char const *file, int line, char const *expr, char const *msg,...))
A fatal assertion which triggers the fault handler in debug builds or exits.
Definition debug.c:1308
int fr_get_lsan_state(void)
Definition debug.c:245
void fr_debug_state_store(void)
Should be run before using setuid or setgid to get useful results.
Definition debug.c:505
void fr_fault(int sig)
Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
Definition debug.c:812
NEVER_RETURNS void _fr_exit(char const *file, int line, int status, bool now)
Exit possibly printing a message about why we're exiting.
Definition debug.c:1340
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition debug.c:1050
void fr_debug_break(bool always)
Break in debugger (if were running under a debugger)
Definition debug.c:554
void fr_fault_set_cb(fr_fault_cb_t func)
Set a callback to be called before fr_fault()
Definition debug.c:1210
void fr_fault_log_hex(uint8_t const *data, size_t data_len)
Print data as a hex block.
Definition debug.c:1238
int fr_set_dumpable_init(void)
Get the current maximum for core files.
Definition debug.c:673
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program, unsigned long fault_signals)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1074
void fr_panic_on_free(TALLOC_CTX *ctx)
Insert memory into the context of another talloc memory chunk which causes a panic when freed.
Definition debug.c:578
fr_debug_state_t fr_debug_state
Whether we're attached to by a debugger.
Definition debug.c:74
int fr_get_debug_state(void)
Definition debug.c:493
Definition dwarf.c:563
unsigned char uint8_t
static char const * program
Definition radiusd.c:79
Signals that can be sent to a request.
void * state
Definition testlib.c:46
static fr_slen_t data
Definition value.h:1340