1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * @file
30 * Cross-platform debugging helpers.
31 *
32 * For now it just has assert and printf replacements, but it might be extended
33 * with stack trace reports and more advanced logging in the near future.
34 *
35 * @author Jose Fonseca <jfonseca@vmware.com>
36 */
37
38 #ifndef U_DEBUG_H_
39 #define U_DEBUG_H_
40
41 #include <stdarg.h>
42 #include <string.h>
43 #if !defined(_WIN32)
44 #include <sys/types.h>
45 #include <unistd.h>
46 #endif
47
48 #include "util/os_misc.h"
49 #include "util/u_atomic.h"
50 #include "util/detect_os.h"
51 #include "util/macros.h"
52
53 #if DETECT_OS_HAIKU
54 /* Haiku provides debug_printf in libroot with OS.h */
55 #include <OS.h>
56 #endif
57
58 #ifdef __cplusplus
59 extern "C" {
60 #endif
61
62 enum util_debug_type
63 {
64 UTIL_DEBUG_TYPE_OUT_OF_MEMORY = 1,
65 UTIL_DEBUG_TYPE_ERROR,
66 UTIL_DEBUG_TYPE_SHADER_INFO,
67 UTIL_DEBUG_TYPE_PERF_INFO,
68 UTIL_DEBUG_TYPE_INFO,
69 UTIL_DEBUG_TYPE_FALLBACK,
70 UTIL_DEBUG_TYPE_CONFORMANCE,
71 };
72
73 /**
74 * Structure that contains a callback for debug messages from the driver back
75 * to the gallium frontend.
76 */
77 struct util_debug_callback
78 {
79 /**
80 * When set to \c true, the callback may be called asynchronously from a
81 * driver-created thread.
82 */
83 bool async;
84
85 /**
86 * Callback for the driver to report debug/performance/etc information back
87 * to the gallium frontend.
88 *
89 * \param data user-supplied data pointer
90 * \param id message type identifier, if pointed value is 0, then a
91 * new id is assigned
92 * \param type UTIL_DEBUG_TYPE_*
93 * \param format printf-style format string
94 * \param args args for format string
95 */
96 void (*debug_message)(void *data,
97 unsigned *id,
98 enum util_debug_type type,
99 const char *fmt,
100 va_list args);
101 void *data;
102 };
103
104 #define _util_printf_format(fmt, list) PRINTFLIKE(fmt, list)
105
106 void _debug_vprintf(const char *format, va_list ap);
107
108
109 static inline void
_debug_printf(const char * format,...)110 _debug_printf(const char *format, ...)
111 {
112 va_list ap;
113 va_start(ap, format);
114 _debug_vprintf(format, ap);
115 va_end(ap);
116 }
117
118
119 /**
120 * Print debug messages.
121 *
122 * The actual channel used to output debug message is platform specific. To
123 * avoid misformating or truncation, follow these rules of thumb:
124 * - output whole lines
125 * - avoid outputing large strings (512 bytes is the current maximum length
126 * that is guaranteed to be printed in all platforms)
127 */
128 #if !DETECT_OS_HAIKU
129 static inline void
130 debug_printf(const char *format, ...) _util_printf_format(1,2);
131
132 static inline void
debug_printf(const char * format,...)133 debug_printf(const char *format, ...)
134 {
135 #ifdef DEBUG
136 va_list ap;
137 va_start(ap, format);
138 _debug_vprintf(format, ap);
139 va_end(ap);
140 #else
141 (void) format; /* silence warning */
142 #endif
143 }
144 #endif
145
146
147 /*
148 * ... isn't portable so we need to pass arguments in parentheses.
149 *
150 * usage:
151 * debug_printf_once(("answer: %i\n", 42));
152 */
153 #define debug_printf_once(args) \
154 do { \
155 static bool once = true; \
156 if (once) { \
157 once = false; \
158 debug_printf args; \
159 } \
160 } while (0)
161
162
163 #ifdef DEBUG
164 #define debug_vprintf(_format, _ap) _debug_vprintf(_format, _ap)
165 #else
166 #define debug_vprintf(_format, _ap) ((void)0)
167 #endif
168
169 #ifdef _WIN32
170 /**
171 * Disable Win32 interactive error message boxes.
172 *
173 * Should be called as soon as possible for effectiveness.
174 */
175 void
176 debug_disable_win32_error_dialogs(void);
177 #endif
178
179
180 /**
181 * Hard-coded breakpoint.
182 */
183 #ifdef DEBUG
184 #define debug_break() os_break()
185 #else /* !DEBUG */
186 #define debug_break() ((void)0)
187 #endif /* !DEBUG */
188
189
190 void
191 debug_get_version_option(const char *name, unsigned *major, unsigned *minor);
192
193
194 /**
195 * Output the current function name.
196 */
197 #ifdef DEBUG
198 #define debug_checkpoint() \
199 _debug_printf("%s\n", __func__)
200 #else
201 #define debug_checkpoint() \
202 ((void)0)
203 #endif
204
205
206 /**
207 * Output the full source code position.
208 */
209 #ifdef DEBUG
210 #define debug_checkpoint_full() \
211 _debug_printf("%s:%u:%s\n", __FILE__, __LINE__, __func__)
212 #else
213 #define debug_checkpoint_full() \
214 ((void)0)
215 #endif
216
217
218 /**
219 * Output a warning message. Muted on release version.
220 */
221 #ifdef DEBUG
222 #define debug_warning(__msg) \
223 _debug_printf("%s:%u:%s: warning: %s\n", __FILE__, __LINE__, __func__, __msg)
224 #else
225 #define debug_warning(__msg) \
226 ((void)0)
227 #endif
228
229
230 /**
231 * Emit a warning message, but only once.
232 */
233 #ifdef DEBUG
234 #define debug_warn_once(__msg) \
235 do { \
236 static bool warned = false; \
237 if (!warned) { \
238 _debug_printf("%s:%u:%s: one time warning: %s\n", \
239 __FILE__, __LINE__, __func__, __msg); \
240 warned = true; \
241 } \
242 } while (0)
243 #else
244 #define debug_warn_once(__msg) \
245 ((void)0)
246 #endif
247
248
249 /**
250 * Output an error message. Not muted on release version.
251 */
252 #ifdef DEBUG
253 #define debug_error(__msg) \
254 _debug_printf("%s:%u:%s: error: %s\n", __FILE__, __LINE__, __func__, __msg)
255 #else
256 #define debug_error(__msg) \
257 _debug_printf("error: %s\n", __msg)
258 #endif
259
260 /**
261 * Output a debug log message to the debug info callback.
262 */
263 #define util_debug_message(cb, type, fmt, ...) do { \
264 static unsigned id = 0; \
265 _util_debug_message(cb, &id, \
266 UTIL_DEBUG_TYPE_ ## type, \
267 fmt, ##__VA_ARGS__); \
268 } while (0)
269
270 void
271 _util_debug_message(
272 struct util_debug_callback *cb,
273 unsigned *id,
274 enum util_debug_type type,
275 const char *fmt, ...) _util_printf_format(4, 5);
276
277
278 /**
279 * Used by debug_dump_enum and debug_dump_flags to describe symbols.
280 */
281 struct debug_named_value
282 {
283 const char *name;
284 uint64_t value;
285 const char *desc;
286 };
287
288
289 /**
290 * Some C pre-processor magic to simplify creating named values.
291 *
292 * Example:
293 * @code
294 * static const debug_named_value my_names[] = {
295 * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_X),
296 * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Y),
297 * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Z),
298 * DEBUG_NAMED_VALUE_END
299 * };
300 *
301 * ...
302 * debug_printf("%s = %s\n",
303 * name,
304 * debug_dump_enum(my_names, my_value));
305 * ...
306 * @endcode
307 */
308 #define DEBUG_NAMED_VALUE(__symbol) {#__symbol, (uint64_t)__symbol, NULL}
309 #define DEBUG_NAMED_VALUE_WITH_DESCRIPTION(__symbol, __desc) {#__symbol, (uint64_t)__symbol, __desc}
310 #define DEBUG_NAMED_VALUE_END {NULL, 0, NULL}
311
312
313 /**
314 * Convert a enum value to a string.
315 */
316 const char *
317 debug_dump_enum(const struct debug_named_value *names,
318 uint64_t value);
319
320 /**
321 * Convert binary flags value to a string.
322 */
323 const char *
324 debug_dump_flags(const struct debug_named_value *names,
325 uint64_t value);
326
327
328 struct debug_control {
329 const char * string;
330 uint64_t flag;
331 };
332
333 uint64_t
334 parse_debug_string(const char *debug,
335 const struct debug_control *control);
336
337
338 uint64_t
339 parse_enable_string(const char *debug,
340 uint64_t default_value,
341 const struct debug_control *control);
342
343
344 bool
345 comma_separated_list_contains(const char *list, const char *s);
346
347 /**
348 * Get option.
349 *
350 * It is an alias for getenv on Unix and Windows.
351 *
352 */
353 const char *
354 debug_get_option(const char *name, const char *dfault);
355
356 const char *
357 debug_get_option_cached(const char *name, const char *dfault);
358
359 bool
360 debug_parse_bool_option(const char *str, bool dfault);
361
362 bool
363 debug_get_bool_option(const char *name, bool dfault);
364
365 int64_t
366 debug_parse_num_option(const char *str, int64_t dfault);
367
368 int64_t
369 debug_get_num_option(const char *name, int64_t dfault);
370
371 uint64_t
372 debug_parse_flags_option(const char *name,
373 const char *str,
374 const struct debug_named_value *flags,
375 uint64_t dfault);
376
377 uint64_t
378 debug_get_flags_option(const char *name,
379 const struct debug_named_value *flags,
380 uint64_t dfault);
381
382 #define DEBUG_GET_ONCE_OPTION(suffix, name, dfault) \
383 static const char * \
384 debug_get_option_ ## suffix (void) \
385 { \
386 static bool initialized = false; \
387 static const char * value; \
388 if (unlikely(!p_atomic_read_relaxed(&initialized))) { \
389 const char *str = debug_get_option_cached(name, dfault); \
390 p_atomic_set(&value, str); \
391 p_atomic_set(&initialized, true); \
392 } \
393 return value; \
394 }
395
396 static inline bool
__check_suid(void)397 __check_suid(void)
398 {
399 #if !defined(_WIN32)
400 if (geteuid() != getuid())
401 return true;
402 #endif
403 return false;
404 }
405
406 #define DEBUG_GET_ONCE_BOOL_OPTION(sufix, name, dfault) \
407 static bool \
408 debug_get_option_ ## sufix (void) \
409 { \
410 static bool initialized = false; \
411 static bool value; \
412 if (unlikely(!p_atomic_read_relaxed(&initialized))) { \
413 const char *str = debug_get_option_cached(name, NULL); \
414 bool parsed_value = debug_parse_bool_option(str, dfault); \
415 p_atomic_set(&value, parsed_value); \
416 p_atomic_set(&initialized, true); \
417 } \
418 return value; \
419 }
420
421 #define DEBUG_GET_ONCE_NUM_OPTION(sufix, name, dfault) \
422 static int64_t \
423 debug_get_option_ ## sufix (void) \
424 { \
425 static bool initialized = false; \
426 static int64_t value; \
427 if (unlikely(!p_atomic_read_relaxed(&initialized))) { \
428 const char *str = debug_get_option_cached(name, NULL); \
429 int64_t parsed_value = debug_parse_num_option(str, dfault); \
430 p_atomic_set(&value, parsed_value); \
431 p_atomic_set(&initialized, true); \
432 } \
433 return value; \
434 }
435
436 #define DEBUG_GET_ONCE_FLAGS_OPTION(sufix, name, flags, dfault) \
437 static uint64_t \
438 debug_get_option_ ## sufix (void) \
439 { \
440 static bool initialized = false; \
441 static uint64_t value; \
442 if (unlikely(!p_atomic_read_relaxed(&initialized))) { \
443 const char *str = debug_get_option_cached(name, NULL); \
444 uint64_t parsed_value = debug_parse_flags_option(name, str, flags, dfault); \
445 p_atomic_set(&value, parsed_value); \
446 p_atomic_set(&initialized, true); \
447 } \
448 return value; \
449 }
450
451
452 #ifdef __cplusplus
453 }
454 #endif
455
456 #endif /* U_DEBUG_H_ */
457