1 // Copyright 2018 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "Debug.hpp"
16
17 #include <atomic>
18 #include <cstdarg>
19 #include <cstdio>
20 #include <string>
21
22 #if __ANDROID__
23 # include <android/log.h>
24 #endif
25
26 #if defined(__unix__)
27 # define PTRACE
28 # include <sys/ptrace.h>
29 # include <sys/types.h>
30 #elif defined(_WIN32) || defined(_WIN64)
31 # include <windows.h>
32 #elif defined(__APPLE__) || defined(__MACH__)
33 # include <sys/sysctl.h>
34 # include <unistd.h>
35 #endif
36
37 #ifdef ERROR
38 # undef ERROR // b/127920555
39 #endif
40
41 #ifndef SWIFTSHADER_LOGGING_LEVEL
42 # define SWIFTSHADER_LOGGING_LEVEL Info
43 #endif
44
45 namespace {
46
IsUnderDebugger()47 bool IsUnderDebugger()
48 {
49 #if defined(PTRACE) && !defined(__APPLE__) && !defined(__MACH__)
50 static bool checked = false;
51 static bool res = false;
52
53 if(!checked)
54 {
55 // If a debugger is attached then we're already being ptraced and ptrace
56 // will return a non-zero value.
57 checked = true;
58 if(ptrace(PTRACE_TRACEME, 0, 1, 0) != 0)
59 {
60 res = true;
61 }
62 else
63 {
64 ptrace(PTRACE_DETACH, 0, 1, 0);
65 }
66 }
67
68 return res;
69 #elif defined(_WIN32) || defined(_WIN64)
70 return IsDebuggerPresent() != 0;
71 #elif defined(__APPLE__) || defined(__MACH__)
72 // Code comes from the Apple Technical Q&A QA1361
73
74 // Tell sysctl what info we're requestion. Specifically we're asking for
75 // info about this our PID.
76 int res = 0;
77 int request[4] = {
78 CTL_KERN,
79 KERN_PROC,
80 KERN_PROC_PID,
81 getpid()
82 };
83 struct kinfo_proc info;
84 size_t size = sizeof(info);
85
86 info.kp_proc.p_flag = 0;
87
88 // Get the info we're requesting, if sysctl fails then info.kp_proc.p_flag will remain 0.
89 res = sysctl(request, sizeof(request) / sizeof(*request), &info, &size, NULL, 0);
90 ASSERT_MSG(res == 0, "syscl returned %d", res);
91
92 // We're being debugged if the P_TRACED flag is set
93 return ((info.kp_proc.p_flag & P_TRACED) != 0);
94 #else
95 return false;
96 #endif
97 }
98
99 enum class Level
100 {
101 Verbose,
102 Debug,
103 Info,
104 Warn,
105 Error,
106 Fatal,
107 Disabled,
108 };
109
110 #ifdef __ANDROID__
logv_android(Level level,const char * msg)111 void logv_android(Level level, const char *msg)
112 {
113 switch(level)
114 {
115 case Level::Debug:
116 __android_log_write(ANDROID_LOG_DEBUG, "SwiftShader", msg);
117 break;
118 case Level::Info:
119 __android_log_write(ANDROID_LOG_INFO, "SwiftShader", msg);
120 break;
121 case Level::Warn:
122 __android_log_write(ANDROID_LOG_WARN, "SwiftShader", msg);
123 break;
124 case Level::Error:
125 __android_log_write(ANDROID_LOG_ERROR, "SwiftShader", msg);
126 break;
127 case Level::Fatal:
128 __android_log_write(ANDROID_LOG_FATAL, "SwiftShader", msg);
129 break;
130 default:
131 break;
132 }
133 }
134 #else
logv_std(Level level,const char * msg)135 void logv_std(Level level, const char *msg)
136 {
137 switch(level)
138 {
139 case Level::Debug:
140 case Level::Info:
141 fprintf(stdout, "%s", msg);
142 break;
143 case Level::Warn:
144 case Level::Error:
145 case Level::Fatal:
146 fprintf(stderr, "%s", msg);
147 break;
148 default:
149 break;
150 }
151 }
152 #endif
153
logv(Level level,const char * format,va_list args)154 void logv(Level level, const char *format, va_list args)
155 {
156 if(static_cast<int>(level) >= static_cast<int>(Level::SWIFTSHADER_LOGGING_LEVEL))
157 {
158 #ifndef SWIFTSHADER_DISABLE_TRACE
159 char buffer[2048];
160 vsnprintf(buffer, sizeof(buffer), format, args);
161
162 # if defined(__ANDROID__)
163 logv_android(level, buffer);
164 # elif defined(_WIN32)
165 logv_std(level, buffer);
166 ::OutputDebugString(buffer);
167 # else
168 logv_std(level, buffer);
169 # endif
170 }
171
172 const Level traceToFileLevel = Level::Disabled;
173 if(static_cast<int>(level) >= static_cast<int>(traceToFileLevel))
174 {
175 FILE *file = fopen(TRACE_OUTPUT_FILE, "a");
176
177 if(file)
178 {
179 vfprintf(file, format, args);
180 fclose(file);
181 }
182 }
183 #endif // SWIFTSHADER_DISABLE_TRACE
184 }
185
186 } // anonymous namespace
187
188 namespace sw {
189
trace(const char * format,...)190 void trace(const char *format, ...)
191 {
192 va_list vararg;
193 va_start(vararg, format);
194 logv(Level::Debug, format, vararg);
195 va_end(vararg);
196 }
197
warn(const char * format,...)198 void warn(const char *format, ...)
199 {
200 va_list vararg;
201 va_start(vararg, format);
202 logv(Level::Warn, format, vararg);
203 va_end(vararg);
204 }
205
abort(const char * format,...)206 void abort(const char *format, ...)
207 {
208 va_list vararg;
209
210 va_start(vararg, format);
211 logv(Level::Fatal, format, vararg);
212 va_end(vararg);
213
214 ::abort();
215 }
216
log_trap(const char * format,...)217 void log_trap(const char *format, ...)
218 {
219 // If enabled, log_assert will log all messages, and otherwise ignore them
220 // unless a debugger is attached.
221 static std::atomic<bool> asserted = { false };
222 if(IsUnderDebugger() && !asserted.exchange(true))
223 {
224 // Abort after tracing and printing to stderr
225 va_list vararg;
226 va_start(vararg, format);
227 logv(Level::Fatal, format, vararg);
228 va_end(vararg);
229
230 ::abort();
231 }
232 else if(!asserted)
233 {
234 va_list vararg;
235 va_start(vararg, format);
236 logv(Level::Verbose, format, vararg);
237 va_end(vararg);
238 }
239 }
240
241 } // namespace sw
242