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