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 REACTOR_LOGGING_LEVEL
42 # define REACTOR_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 Debug,
102 Info,
103 Warn,
104 Error,
105 Fatal,
106 };
107
108 #ifdef __ANDROID__
logv_android(Level level,const char * msg)109 [[maybe_unused]] void logv_android(Level level, const char *msg)
110 {
111 switch(level)
112 {
113 case Level::Debug:
114 __android_log_write(ANDROID_LOG_DEBUG, "SwiftShader", msg);
115 break;
116 case Level::Info:
117 __android_log_write(ANDROID_LOG_INFO, "SwiftShader", msg);
118 break;
119 case Level::Warn:
120 __android_log_write(ANDROID_LOG_WARN, "SwiftShader", msg);
121 break;
122 case Level::Error:
123 __android_log_write(ANDROID_LOG_ERROR, "SwiftShader", msg);
124 break;
125 case Level::Fatal:
126 __android_log_write(ANDROID_LOG_FATAL, "SwiftShader", msg);
127 break;
128 }
129 }
130 #else
logv_std(Level level,const char * msg)131 [[maybe_unused]] void logv_std(Level level, const char *msg)
132 {
133 switch(level)
134 {
135 case Level::Debug:
136 case Level::Info:
137 fprintf(stdout, "%s", msg);
138 break;
139 case Level::Warn:
140 case Level::Error:
141 case Level::Fatal:
142 fprintf(stderr, "%s", msg);
143 break;
144 }
145 }
146 #endif
147
logv(Level level,const char * format,va_list args)148 void logv(Level level, const char *format, va_list args)
149 {
150 if(static_cast<int>(level) < static_cast<int>(Level::REACTOR_LOGGING_LEVEL))
151 {
152 return;
153 }
154
155 #ifndef SWIFTSHADER_DISABLE_TRACE
156 char buffer[2048];
157 vsnprintf(buffer, sizeof(buffer), format, args);
158
159 # if defined(__ANDROID__)
160 logv_android(level, buffer);
161 # elif defined(_WIN32)
162 logv_std(level, buffer);
163 ::OutputDebugString(buffer);
164 # else
165 logv_std(level, buffer);
166 # endif
167
168 const bool traceToFile = false;
169 if(traceToFile)
170 {
171 FILE *file = fopen(TRACE_OUTPUT_FILE, "a");
172
173 if(file)
174 {
175 vfprintf(file, format, args);
176 fclose(file);
177 }
178 }
179 #endif // SWIFTSHADER_DISABLE_TRACE
180 }
181
182 } // anonymous namespace
183
184 namespace rr {
185
trace(const char * format,...)186 void trace(const char *format, ...)
187 {
188 va_list vararg;
189 va_start(vararg, format);
190 logv(Level::Debug, format, vararg);
191 va_end(vararg);
192 }
193
warn(const char * format,...)194 void warn(const char *format, ...)
195 {
196 va_list vararg;
197 va_start(vararg, format);
198 logv(Level::Warn, format, vararg);
199 va_end(vararg);
200 }
201
abort(const char * format,...)202 void abort(const char *format, ...)
203 {
204 va_list vararg;
205
206 va_start(vararg, format);
207 logv(Level::Fatal, format, vararg);
208 va_end(vararg);
209
210 ::abort();
211 }
212
trace_assert(const char * format,...)213 void trace_assert(const char *format, ...)
214 {
215 static std::atomic<bool> asserted = { false };
216 if(IsUnderDebugger() && !asserted.exchange(true))
217 {
218 // Abort after tracing and printing to stderr
219 va_list vararg;
220 va_start(vararg, format);
221 logv(Level::Fatal, format, vararg);
222 va_end(vararg);
223
224 ::abort();
225 }
226 else if(!asserted)
227 {
228 va_list vararg;
229 va_start(vararg, format);
230 logv(Level::Fatal, format, vararg);
231 va_end(vararg);
232 }
233 }
234
235 } // namespace rr
236