1 /*
2  * Copyright (c) 2012 Apple Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
19  * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Except as contained in this notice, the name(s) of the above
25  * copyright holders shall not be used in advertising or otherwise to
26  * promote the sale, use or other dealings in this Software without
27  * prior written authorization.
28  */
29 
30 #include <sys/cdefs.h>
31 #include <asl.h>
32 #include <stdio.h>
33 #include <stdbool.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <inttypes.h>
37 #include <pthread.h>
38 #include "apple_glx_log.h"
39 #include "util/debug.h"
40 
41 static bool diagnostic = false;
42 static aslclient aslc;
43 
apple_glx_log_init(void)44 void apple_glx_log_init(void) {
45     if (env_var_as_boolean("LIBGL_DIAGNOSTIC", false)) {
46         diagnostic = true;
47     }
48 
49     aslc = asl_open(NULL, NULL, 0);
50 }
51 
_apple_glx_log(int level,const char * file,const char * function,int line,const char * fmt,...)52 void _apple_glx_log(int level, const char *file, const char *function,
53                     int line, const char *fmt, ...) {
54     va_list v;
55     va_start(v, fmt);
56     _apple_glx_vlog(level, file, function, line, fmt, v);
57     va_end(v);
58 }
59 
60 static const char *
_asl_level_string(int level)61 _asl_level_string(int level)
62 {
63         if (level == ASL_LEVEL_EMERG) return ASL_STRING_EMERG;
64         if (level == ASL_LEVEL_ALERT) return ASL_STRING_ALERT;
65         if (level == ASL_LEVEL_CRIT) return ASL_STRING_CRIT;
66         if (level == ASL_LEVEL_ERR) return ASL_STRING_ERR;
67         if (level == ASL_LEVEL_WARNING) return ASL_STRING_WARNING;
68         if (level == ASL_LEVEL_NOTICE) return ASL_STRING_NOTICE;
69         if (level == ASL_LEVEL_INFO) return ASL_STRING_INFO;
70         if (level == ASL_LEVEL_DEBUG) return ASL_STRING_DEBUG;
71         return "unknown";
72 }
73 
_apple_glx_vlog(int level,const char * file,const char * function,int line,const char * fmt,va_list args)74 void _apple_glx_vlog(int level, const char *file, const char *function,
75                      int line, const char *fmt, va_list args) {
76     aslmsg msg;
77     uint64_t thread = 0;
78 
79     if (pthread_is_threaded_np()) {
80 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
81         thread = (uint64_t)(uintptr_t)pthread_self();
82 #elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060
83         if (&pthread_threadid_np) {
84             pthread_threadid_np(NULL, &thread);
85         } else {
86             thread = (uint64_t)(uintptr_t)pthread_self();
87         }
88 #else
89         pthread_threadid_np(NULL, &thread);
90 #endif
91     }
92 
93     if (diagnostic) {
94         va_list args2;
95         va_copy(args2, args);
96 
97         fprintf(stderr, "%-9s %24s:%-4d %s(%"PRIu64"): ",
98                 _asl_level_string(level), file, line, function, thread);
99         vfprintf(stderr, fmt, args2);
100         va_end(args2);
101     }
102 
103     msg = asl_new(ASL_TYPE_MSG);
104     if (msg) {
105         if (file)
106             asl_set(msg, "File", file);
107         if (function)
108             asl_set(msg, "Function", function);
109         if (line) {
110             char *_line;
111             asprintf(&_line, "%d", line);
112             if (_line) {
113                 asl_set(msg, "Line", _line);
114                 free(_line);
115             }
116         }
117         if (pthread_is_threaded_np()) {
118             char *_thread;
119             asprintf(&_thread, "%"PRIu64, thread);
120             if (_thread) {
121                 asl_set(msg, "Thread", _thread);
122                 free(_thread);
123             }
124         }
125     }
126 
127     asl_vlog(aslc, msg, level, fmt, args);
128     if (msg)
129         asl_free(msg);
130 }
131