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