xref: /aosp_15_r20/external/mesa3d/src/util/u_debug.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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