The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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
25 extern "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 
39 typedef 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 
48 
49 #define FR_FAULT_LOG(_fmt, ...) fr_fault_log(_fmt "\n", ## __VA_ARGS__)
50 #define FR_FAULT_LOG_HEX(_data, _data_len) fr_fault_log_hex(_data, _data_len)
51 
52 /** Optional callback passed to fr_fault_setup
53  *
54  * Allows optional logic to be run before calling the main fault handler.
55  *
56  * If the callback returns < 0, the main fault handler will not be called.
57  *
58  * @param signum signal raised.
59  * @return
60  * - 0 on success.
61  * - < 0 on failure.
62  */
63 typedef int (*fr_fault_cb_t)(int signum);
64 typedef struct fr_bt_marker fr_bt_marker_t;
65 
66 int fr_get_lsan_state(void);
67 
68 int fr_get_debug_state(void);
69 
70 void fr_debug_state_store(void);
71 
72 char const *fr_debug_state_to_msg(fr_debug_state_t state);
73 
74 void fr_debug_break(bool always);
75 
76 void backtrace_print(fr_fring_t *fring, void *obj);
77 
79 
80 fr_bt_marker_t *fr_backtrace_attach(fr_fring_t **fring, TALLOC_CTX *obj);
81 
82 void fr_panic_on_free(TALLOC_CTX *ctx);
83 
84 int fr_set_dumpable_init(void);
85 
86 int fr_set_dumpable(bool allow_core_dumps);
87 
88 int fr_reset_dumpable(void);
89 
90 int fr_log_talloc_report(TALLOC_CTX const *ctx);
91 
92 void fr_fault(int sig);
93 
94 void fr_talloc_fault_setup(void);
95 
96 void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx);
97 
98 int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program);
99 
100 void fr_fault_set_cb(fr_fault_cb_t func);
101 
102 void fr_fault_set_log_fd(int fd);
103 
104 void fr_fault_log(char const *msg, ...) CC_HINT(format (printf, 1, 2));
105 
106 void fr_fault_log_hex(uint8_t const *data, size_t data_len);
107 
108 /** @name Assertion support functions
109  * @{
110  */
111 bool _fr_assert_fail(char const *file, int line, char const *expr, char const *msg, ...)
112  CC_HINT(format (printf, 4, 5));
113 
114 NEVER_RETURNS void _fr_assert_fatal(char const *file, int line, char const *expr, char const *msg, ...)
115  CC_HINT(format (printf, 4, 5));
116 
117 NEVER_RETURNS void _fr_exit(char const *file, int line, int status, bool now);
118 /** @} */
119 
120 /** @name Assertion and exit macros
121  * @{
122  */
123 
124 /** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x
125  *
126  * Should be wrapped in a condition, and if false, should cause function to return
127  * an error code. This allows control to return to the caller if a precondition is
128  * not satisfied and we're not debugging.
129  *
130  * Example:
131  @verbatim
132  if (!fr_cond_assert(request)) return -1
133  @endverbatim
134  *
135  * @param[in] _x expression to test (should evaluate to true)
136  */
137 #define fr_cond_assert(_x) likely((bool)((_x) ? true : (_fr_assert_fail(__FILE__, __LINE__, #_x, NULL) && false)))
138 
139 /** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x
140  *
141  * Should be wrapped in a condition, and if false, should cause function to return
142  * an error code. This allows control to return to the caller if a precondition is
143  * not satisfied and we're not debugging.
144  *
145  * Example:
146  @verbatim
147  if (!fr_cond_assert_msg(request, "Bad stuff happened: %s", fr_syserror(errno)))) return -1
148  @endverbatim
149  *
150  * @param[in] _x expression to test (should evaluate to true)
151  * @param[in] _fmt of message to log.
152  * @param[in] ... fmt arguments.
153  */
154 #define fr_cond_assert_msg(_x, _fmt, ...) likely((bool)((_x) ? true : (_fr_assert_fail(__FILE__, __LINE__, #_x, _fmt, ## __VA_ARGS__) && false)))
155 
156 /** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
157  *
158  * Example:
159  @verbatim
160  fr_fatal_assert(<extremely_unlikely_and_fatal_condition>);
161  @endverbatim
162  *
163  * @param _x expression to test (should evaluate to true)
164  */
165 #define fr_fatal_assert(_x) if (unlikely(!((bool)(_x)))) _fr_assert_exit(__FILE__, __LINE__, #_x, NULL))
166 
167 /** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
168  *
169  * Should be wrapped in a condition, and if false, should cause function to return
170  * an error code. This allows control to return to the caller if a precondition is
171  * not satisfied and we're not debugging.
172  *
173  * Example:
174  @verbatim
175  fr_fatal_assert(<extremely_unlikely_and_fatal_condition>);
176  @endverbatim
177  *
178  * @param[in] _x expression to test (should evaluate to true)
179  * @param[in] _fmt of message to log.
180  * @param[in] ... fmt arguments.
181  */
182 #define fr_fatal_assert_msg(_x, _fmt, ...) if (unlikely(!((bool)(_x)))) _fr_assert_fatal(__FILE__, __LINE__, #_x, _fmt, ## __VA_ARGS__)
183 
184 /** Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code 134
185  *
186  * @param[in] _msg to log.
187  * @param[in] ... args.
188  */
189 #define fr_fatal_assert_fail(_msg, ...) _fr_assert_fatal(__FILE__, __LINE__, "false", _msg, ## __VA_ARGS__)
190 
191 #ifdef NDEBUG
192 # define fr_assert(_x)
193 # define fr_assert_msg(_x, _msg, ...)
194 # define fr_assert_fail(_msg, ...)
195 #elif !defined(STATIC_ANALYZER)
196 /** Calls panic_action ifndef NDEBUG, else logs error
197  *
198  * @param[in] _x expression to test (should evaluate to true)
199  */
200 # define fr_assert(_x) if (unlikely(!((bool)(_x)))) _fr_assert_fail(__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  * @param[in] _x expression to test (should evaluate to true)
205  * @param[in] _msg to log.
206  * @param[in] ... args.
207  */
208 # define fr_assert_msg(_x, _msg, ...) if (unlikely(!((bool)(_x)))) _fr_assert_fail(__FILE__, __LINE__, #_x, _msg, ## __VA_ARGS__)
209 /** Calls panic_action ifndef NDEBUG, else logs error
210  *
211  * @param[in] _msg to log.
212  * @param[in] ... args.
213  */
214 #define fr_assert_fail(_msg, ...) _fr_assert_fail(__FILE__, __LINE__, "false", _msg, ## __VA_ARGS__)
215 #else
216 # include <assert.h>
217 # define fr_assert(_x) assert(_x)
218 # define fr_assert_msg(_x, _msg, ...) assert(_x)
219 # define fr_assert_fail(_msg ...) assert(0)
220 #endif
221 
222 /** Exit, producing a log message in debug builds
223  *
224  * @param[in] _x code to exit with.
225  */
226 # define fr_exit(_x) _fr_exit(__FILE__, __LINE__, (_x), false)
227 
228 /** Exit without calling atexit() handlers, producing a log message in debug builds
229  *
230  * @param[in] _x code to exit with.
231  */
232 # define fr_exit_now(_x) _fr_exit(__FILE__, __LINE__, (_x), true)
233 /** @} */
234 
235 void fr_sign_struct(void *ptr, size_t size, size_t offset);
236 void fr_verify_struct(void const *ptr, size_t size, size_t offset);
237 void fr_verify_struct_member(void const *ptr, size_t len, uint32_t *signature);
238 
239 /** Manual validation of structures.
240  *
241  * typedef struct {
242  * char *a;
243  * int b;
244  * FR_SIGNATURE // no semicolon!
245  * } foo_t;
246  *
247  * and then once the structure is initialized (and will never be changed)
248  *
249  * foo_t *ptr;
250  * FR_STRUCT_SIGN(ptr);
251  *
252  * and some time later...
253  *
254  * foo_t *ptr;
255  * FR_STRUCT_VERIFY(ptr);
256  *
257  * Note that the structure can't contain variable elements such as fr_dlist_t.
258  * And that we're not verifying the contents of the members which are pointers.
259  */
260 #ifndef NDEBUG
261 #define FR_STRUCT_SIGN(_ptr) fr_sign_struct(_ptr, sizeof(__typeof__(*_ptr)), offsetof(__typeof__(*_ptr), _signature));
262 #define FR_STRUCT_VERIFY(_ptr) fr_verify_struct(_ptr, sizeof(__typeof__(*_ptr)), offsetof(__typeof__(*_ptr), _signature))
263 #define FR_STRUCT_SIGNATURE uint32_t _signature;
264 
265 #define FR_STRUCT_MEMBER_SIGN(_ptr, _member, _len) _ptr->_signature_##_member = fr_hash(_ptr->_member, _len)
266 #define FR_STRUCT_MEMBER_VERIFY(_ptr, _member, _len) fr_verify_struct_member(_ptr->_member, _len, &(_ptr->_signature_##_member))
267 #define FR_STRUCT_MEMBER_SIGNATURE(_member) uint32_t _signature_##_member;
268 #else
269 #define FR_STRUCT_SIGN(_ptr)
270 #define FR_STRUCT_VERIFY(_ptr)
271 #define FR_STRUCT_SIGNATURE
272 
273 #define FR_STRUCT_MEMBER_SIGN(_ptr, _member, _len)
274 #define FR_STRUCT_MEMBER_VERIFY(_ptr, _member, _len)
275 #define FR_STRUCT_MEMBER_SIGNATURE(_member)
276 #endif
277 
278 #ifdef __cplusplus
279 }
280 #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:311
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:1422
char const * fr_debug_state_to_msg(fr_debug_state_t state)
Return current value of debug_state.
Definition: debug.c:524
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:1180
fr_bt_marker_t * fr_backtrace_attach(fr_fring_t **fring, TALLOC_CTX *obj)
void fr_fault_set_log_fd(int fd)
Set a file descriptor to log memory reports to.
Definition: debug.c:1408
struct fr_bt_marker fr_bt_marker_t
Definition: debug.h:64
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:1120
int fr_set_dumpable(bool allow_core_dumps)
Enable or disable core dumps.
Definition: debug.c:805
void fr_verify_struct(void const *ptr, size_t size, size_t offset)
Definition: debug.c:1542
void fr_fault_log(char const *msg,...))
Log output to the fr_fault_log_fd.
Definition: debug.c:1374
int(* fr_fault_cb_t)(int signum)
Optional callback passed to fr_fault_setup.
Definition: debug.h:63
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
Definition: debug.c:873
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:1215
void fr_verify_struct_member(void const *ptr, size_t len, uint32_t *signature)
Definition: debug.c:1551
void fr_sign_struct(void *ptr, size_t size, size_t offset)
Definition: debug.c:1537
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:1458
int fr_get_lsan_state(void)
Definition: debug.c:261
void fr_debug_state_store(void)
Should be run before using setuid or setgid to get useful results.
Definition: debug.c:504
void fr_fault(int sig)
Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
Definition: debug.c:929
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:1490
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition: debug.c:1196
void fr_debug_break(bool always)
Break in debugger (if were running under a debugger)
Definition: debug.c:553
void fr_fault_set_cb(fr_fault_cb_t func)
Set a callback to be called before fr_fault()
Definition: debug.c:1360
void fr_fault_log_hex(uint8_t const *data, size_t data_len)
Print data as a hex block.
Definition: debug.c:1388
int fr_set_dumpable_init(void)
Get the current maximum for core files.
Definition: debug.c:790
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:695
fr_debug_state_t fr_debug_state
Whether we're attached to by a debugger.
Definition: debug.c:104
int fr_backtrace_do(fr_bt_marker_t *marker)
int fr_get_debug_state(void)
Definition: debug.c:492
void backtrace_print(fr_fring_t *fring, void *obj)
Standard thread safe circular buffer.
Definition: fring.c:36
unsigned int uint32_t
Definition: merged_model.c:33
unsigned char uint8_t
Definition: merged_model.c:30
static fr_slen_t data
Definition: value.h:1259
int format(printf, 5, 0))