The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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/fring.h>
31
32#ifdef NO_ASSERT
33# define MEM(x) error "Use of MEM() not allowed in this source file. Deal with memory allocation failure gracefully"
34#else
35/* Short circuit condition to prevent duplicate evaluation */
36# define MEM(x) do { if (!(x)) { fr_cond_assert_msg(0 && (x), "OUT OF MEMORY"); _fr_exit(__FILE__, __LINE__, EXIT_FAILURE, true); } } while (0)
37#endif
38
39typedef enum {
40 DEBUGGER_STATE_UNKNOWN_NO_PTRACE = -3, //!< We don't have ptrace so can't check.
41 DEBUGGER_STATE_UNKNOWN_NO_PTRACE_CAP = -2, //!< CAP_SYS_PTRACE not set for the process.
42 DEBUGGER_STATE_UNKNOWN = -1, //!< Unknown, likely fr_get_debug_state() not called yet.
43 DEBUGGER_STATE_NOT_ATTACHED = 0, //!< We can attach, so a debugger must not be.
44 DEBUGGER_STATE_ATTACHED = 1 //!< We can't attach, it's likely a debugger is already tracing.
46
47extern int fr_fault_log_fd;
49
50#define FR_FAULT_LOG(_fmt, ...) fr_fault_log(_fmt "\n", ## __VA_ARGS__)
51#define FR_FAULT_LOG_HEX(_data, _data_len) fr_fault_log_hex(_data, _data_len)
52
53/** Optional callback passed to fr_fault_setup
54 *
55 * Allows optional logic to be run before calling the main fault handler.
56 *
57 * If the callback returns < 0, the main fault handler will not be called.
58 *
59 * @param signum signal raised.
60 * @return
61 * - 0 on success.
62 * - < 0 on failure.
63 */
64typedef int (*fr_fault_cb_t)(int signum);
65
66int fr_get_lsan_state(void);
67
68int fr_get_debug_state(void);
69
70void fr_debug_state_store(void);
71
73
74void fr_debug_break(bool always);
75
76void fr_panic_on_free(TALLOC_CTX *ctx);
77
78int fr_set_dumpable_init(void);
79
80int fr_set_dumpable(bool allow_core_dumps);
81
82int fr_reset_dumpable(void);
83
84int fr_log_talloc_report(TALLOC_CTX const *ctx);
85
86void fr_fault(int sig);
87
88void fr_talloc_fault_setup(void);
89
90void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx);
91
92int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program);
93
95
96void fr_fault_set_log_fd(int fd);
97
98void fr_fault_log(char const *msg, ...) CC_HINT(format (printf, 1, 2));
99
100void fr_fault_log_hex(uint8_t const *data, size_t data_len);
101
102/** @name Assertion support functions
103 * @{
104 */
105bool _fr_assert_fail(char const *file, int line, char const *expr, char const *msg, ...)
106 CC_HINT(format (printf, 4, 5));
107
108NEVER_RETURNS void _fr_assert_fatal(char const *file, int line, char const *expr, char const *msg, ...)
109 CC_HINT(format (printf, 4, 5));
110
111NEVER_RETURNS void _fr_exit(char const *file, int line, int status, bool now);
112/** @} */
113
114/** @name Assertion and exit macros
115 * @{
116 */
117
118/** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x
119 *
120 * Should be wrapped in a condition, and if false, should cause function to return
121 * an error code. This allows control to return to the caller if a precondition is
122 * not satisfied and we're not debugging.
123 *
124 * Example:
125 @verbatim
126 if (!fr_cond_assert(request)) return -1
127 @endverbatim
128 *
129 * @param[in] _x expression to test (should evaluate to true)
130 */
131#define fr_cond_assert(_x) likely((bool)((_x) ? true : (_fr_assert_fail(__FILE__, __LINE__, #_x, NULL) && false)))
132
133/** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x
134 *
135 * Should be wrapped in a condition, and if false, should cause function to return
136 * an error code. This allows control to return to the caller if a precondition is
137 * not satisfied and we're not debugging.
138 *
139 * Example:
140 @verbatim
141 if (!fr_cond_assert_msg(request, "Bad stuff happened: %s", fr_syserror(errno)))) return -1
142 @endverbatim
143 *
144 * @param[in] _x expression to test (should evaluate to true)
145 * @param[in] _fmt of message to log.
146 * @param[in] ... fmt arguments.
147 */
148#define fr_cond_assert_msg(_x, _fmt, ...) likely((bool)((_x) ? true : (_fr_assert_fail(__FILE__, __LINE__, #_x, _fmt, ## __VA_ARGS__) && false)))
149
150/** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
151 *
152 * Example:
153 @verbatim
154 fr_fatal_assert(<extremely_unlikely_and_fatal_condition>);
155 @endverbatim
156 *
157 * @param _x expression to test (should evaluate to true)
158 */
159#define fr_fatal_assert(_x) if (unlikely(!((bool)(_x)))) _fr_assert_fatal(__FILE__, __LINE__, #_x, NULL)
160
161/** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
162 *
163 * Should be wrapped in a condition, and if false, should cause function to return
164 * an error code. This allows control to return to the caller if a precondition is
165 * not satisfied and we're not debugging.
166 *
167 * Example:
168 @verbatim
169 fr_fatal_assert(<extremely_unlikely_and_fatal_condition>);
170 @endverbatim
171 *
172 * @param[in] _x expression to test (should evaluate to true)
173 * @param[in] _fmt of message to log.
174 * @param[in] ... fmt arguments.
175 */
176#define fr_fatal_assert_msg(_x, _fmt, ...) if (unlikely(!((bool)(_x)))) _fr_assert_fatal(__FILE__, __LINE__, #_x, _fmt, ## __VA_ARGS__)
177
178/** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
179 *
180 * @param[in] _msg to log.
181 * @param[in] ... args.
182 */
183#define fr_fatal_assert_fail(_msg, ...) _fr_assert_fatal(__FILE__, __LINE__, "false", _msg, ## __VA_ARGS__)
184
185#ifdef NDEBUG
186# define fr_assert(_x)
187# define fr_assert_msg(_x, _msg, ...)
188# define fr_assert_fail(_msg, ...)
189#elif !defined(STATIC_ANALYZER)
190/** Calls panic_action ifndef NDEBUG, else logs error
191 *
192 * @param[in] _x expression to test (should evaluate to true)
193 */
194# define fr_assert(_x) if (unlikely(!((bool)(_x)))) _fr_assert_fail(__FILE__, __LINE__, #_x, NULL)
195
196/** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
197 *
198 * @param[in] _x expression to test (should evaluate to true)
199 * @param[in] _msg to log.
200 * @param[in] ... args.
201 */
202# define fr_assert_msg(_x, _msg, ...) if (unlikely(!((bool)(_x)))) _fr_assert_fail(__FILE__, __LINE__, #_x, _msg, ## __VA_ARGS__)
203/** Calls panic_action ifndef NDEBUG, else logs error
204 *
205 * @param[in] _msg to log.
206 * @param[in] ... args.
207 */
208#define fr_assert_fail(_msg, ...) _fr_assert_fail(__FILE__, __LINE__, "false", _msg, ## __VA_ARGS__)
209#else
210# include <assert.h>
211# define fr_assert(_x) assert(_x)
212# define fr_assert_msg(_x, _msg, ...) assert(_x)
213# define fr_assert_fail(_msg ...) assert(0)
214#endif
215
216/** Exit, producing a log message in debug builds
217 *
218 * @param[in] _x code to exit with.
219 */
220# define fr_exit(_x) _fr_exit(__FILE__, __LINE__, (_x), false)
221
222/** Exit without calling atexit() handlers, producing a log message in debug builds
223 *
224 * @param[in] _x code to exit with.
225 */
226# define fr_exit_now(_x) _fr_exit(__FILE__, __LINE__, (_x), true)
227/** @} */
228
229void fr_sign_struct(void *ptr, size_t size, size_t offset);
230void fr_verify_struct(void const *ptr, size_t size, size_t offset);
231void fr_verify_struct_member(void const *ptr, size_t len, uint32_t *signature);
232
233/** Manual validation of structures.
234 *
235 * typedef struct {
236 * char *a;
237 * int b;
238 * FR_SIGNATURE // no semicolon!
239 * } foo_t;
240 *
241 * and then once the structure is initialized (and will never be changed)
242 *
243 * foo_t *ptr;
244 * FR_STRUCT_SIGN(ptr);
245 *
246 * and some time later...
247 *
248 * foo_t *ptr;
249 * FR_STRUCT_VERIFY(ptr);
250 *
251 * Note that the structure can't contain variable elements such as fr_dlist_t.
252 * And that we're not verifying the contents of the members which are pointers.
253 */
254#ifndef NDEBUG
255#define FR_STRUCT_SIGN(_ptr) fr_sign_struct(_ptr, sizeof(__typeof__(*_ptr)), offsetof(__typeof__(*_ptr), _signature));
256#define FR_STRUCT_VERIFY(_ptr) fr_verify_struct(_ptr, sizeof(__typeof__(*_ptr)), offsetof(__typeof__(*_ptr), _signature))
257#define FR_STRUCT_SIGNATURE uint32_t _signature;
258
259#define FR_STRUCT_MEMBER_SIGN(_ptr, _member, _len) _ptr->_signature_##_member = fr_hash(_ptr->_member, _len)
260#define FR_STRUCT_MEMBER_VERIFY(_ptr, _member, _len) fr_verify_struct_member(_ptr->_member, _len, &(_ptr->_signature_##_member))
261#define FR_STRUCT_MEMBER_SIGNATURE(_member) uint32_t _signature_##_member;
262#else
263#define FR_STRUCT_SIGN(_ptr)
264#define FR_STRUCT_VERIFY(_ptr)
265#define FR_STRUCT_SIGNATURE
266
267#define FR_STRUCT_MEMBER_SIGN(_ptr, _member, _len)
268#define FR_STRUCT_MEMBER_VERIFY(_ptr, _member, _len)
269#define FR_STRUCT_MEMBER_SIGNATURE(_member)
270#endif
271
272#ifdef __cplusplus
273}
274#endif
int const char * file
Definition acutest.h:702
log_entry msg
Definition acutest.h:794
int const char int line
Definition acutest.h:702
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:315
char const * fr_debug_state_to_msg(fr_debug_state_t state)
Return current value of debug_state.
Definition debug.c:511
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:1246
fr_debug_state_t
Definition debug.h:39
@ DEBUGGER_STATE_NOT_ATTACHED
We can attach, so a debugger must not be.
Definition debug.h:43
@ DEBUGGER_STATE_UNKNOWN_NO_PTRACE
We don't have ptrace so can't check.
Definition debug.h:40
@ DEBUGGER_STATE_UNKNOWN_NO_PTRACE_CAP
CAP_SYS_PTRACE not set for the process.
Definition debug.h:41
@ DEBUGGER_STATE_UNKNOWN
Unknown, likely fr_get_debug_state() not called yet.
Definition debug.h:42
@ DEBUGGER_STATE_ATTACHED
We can't attach, it's likely a debugger is already tracing.
Definition debug.h:44
void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx)
Disable the null tracking context when a talloc chunk is freed.
Definition debug.c:1020
void fr_fault_set_log_fd(int fd)
Set a file descriptor to log memory reports to.
Definition debug.c:1232
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:961
int fr_set_dumpable(bool allow_core_dumps)
Enable or disable core dumps.
Definition debug.c:674
void fr_verify_struct(void const *ptr, size_t size, size_t offset)
Definition debug.c:1366
void fr_fault_log(char const *msg,...))
Log output to the fr_fault_log_fd.
Definition debug.c:1198
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:64
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
Definition debug.c:742
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1055
void fr_verify_struct_member(void const *ptr, size_t len, uint32_t *signature)
Definition debug.c:1375
void fr_sign_struct(void *ptr, size_t size, size_t offset)
Definition debug.c:1361
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:1282
int fr_get_lsan_state(void)
Definition debug.c:231
void fr_debug_state_store(void)
Should be run before using setuid or setgid to get useful results.
Definition debug.c:491
void fr_fault(int sig)
Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
Definition debug.c:798
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:1314
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition debug.c:1036
void fr_debug_break(bool always)
Break in debugger (if were running under a debugger)
Definition debug.c:540
void fr_fault_set_cb(fr_fault_cb_t func)
Set a callback to be called before fr_fault()
Definition debug.c:1184
void fr_fault_log_hex(uint8_t const *data, size_t data_len)
Print data as a hex block.
Definition debug.c:1212
int fr_set_dumpable_init(void)
Get the current maximum for core files.
Definition debug.c:659
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:564
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:479
unsigned int uint32_t
unsigned char uint8_t
char const * program
Definition radiusd.c:85
static fr_slen_t data
Definition value.h:1291