1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // debug.cpp: Debugging utilities.
8
9 #include "common/debug.h"
10
11 #include <stdarg.h>
12
13 #include <array>
14 #include <cstdio>
15 #include <fstream>
16 #include <mutex>
17 #include <ostream>
18 #include <vector>
19
20 #if defined(ANGLE_PLATFORM_ANDROID)
21 # include <android/log.h>
22 #endif
23
24 #if defined(ANGLE_PLATFORM_APPLE)
25 # include <os/log.h>
26 #endif
27
28 #include "anglebase/no_destructor.h"
29 #include "common/Optional.h"
30 #include "common/angleutils.h"
31 #include "common/system_utils.h"
32
33 namespace gl
34 {
35
36 namespace
37 {
38
39 DebugAnnotator *g_debugAnnotator = nullptr;
40
41 std::mutex *g_debugMutex = nullptr;
42
43 constexpr std::array<const char *, LOG_NUM_SEVERITIES> g_logSeverityNames = {
44 {"EVENT", "INFO", "WARN", "ERR", "FATAL"}};
45
LogSeverityName(int severity)46 constexpr const char *LogSeverityName(int severity)
47 {
48 return (severity >= 0 && severity < LOG_NUM_SEVERITIES) ? g_logSeverityNames[severity]
49 : "UNKNOWN";
50 }
51
ShouldCreateLogMessage(LogSeverity severity)52 bool ShouldCreateLogMessage(LogSeverity severity)
53 {
54 #if defined(ANGLE_TRACE_ENABLED)
55 return true;
56 #elif defined(ANGLE_ENABLE_ASSERTS)
57 return severity == LOG_FATAL || severity == LOG_ERR || severity == LOG_WARN;
58 #else
59 return false;
60 #endif
61 }
62
63 } // namespace
64
65 namespace priv
66 {
67
ShouldCreatePlatformLogMessage(LogSeverity severity)68 bool ShouldCreatePlatformLogMessage(LogSeverity severity)
69 {
70 #if defined(ANGLE_TRACE_ENABLED)
71 return true;
72 #else
73 return severity != LOG_EVENT;
74 #endif
75 }
76
77 // This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to an object of the correct
78 // type on the LHS of the unused part of the ternary operator.
79 std::ostream *gSwallowStream;
80 } // namespace priv
81
DebugAnnotationsActive()82 bool DebugAnnotationsActive()
83 {
84 #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
85 return g_debugAnnotator != nullptr && g_debugAnnotator->getStatus();
86 #else
87 return false;
88 #endif
89 }
90
DebugAnnotationsInitialized()91 bool DebugAnnotationsInitialized()
92 {
93 return g_debugAnnotator != nullptr;
94 }
95
InitializeDebugAnnotations(DebugAnnotator * debugAnnotator)96 void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator)
97 {
98 UninitializeDebugAnnotations();
99 g_debugAnnotator = debugAnnotator;
100 }
101
UninitializeDebugAnnotations()102 void UninitializeDebugAnnotations()
103 {
104 // Pointer is not managed.
105 g_debugAnnotator = nullptr;
106 }
107
InitializeDebugMutexIfNeeded()108 void InitializeDebugMutexIfNeeded()
109 {
110 if (g_debugMutex == nullptr)
111 {
112 g_debugMutex = new std::mutex();
113 }
114 }
115
ScopedPerfEventHelper(const char * format,...)116 ScopedPerfEventHelper::ScopedPerfEventHelper(const char *format, ...) : mFunctionName(nullptr)
117 {
118 bool dbgTrace = DebugAnnotationsActive();
119 #if !defined(ANGLE_ENABLE_DEBUG_TRACE)
120 if (!dbgTrace)
121 {
122 return;
123 }
124 #endif // !ANGLE_ENABLE_DEBUG_TRACE
125
126 va_list vararg;
127 va_start(vararg, format);
128 std::vector<char> buffer(512);
129 size_t len = FormatStringIntoVector(format, vararg, buffer);
130 ANGLE_LOG(EVENT) << std::string(&buffer[0], len);
131 // Pull function name from variable args
132 mFunctionName = va_arg(vararg, const char *);
133 va_end(vararg);
134 if (dbgTrace)
135 {
136 g_debugAnnotator->beginEvent(mFunctionName, buffer.data());
137 }
138 }
139
~ScopedPerfEventHelper()140 ScopedPerfEventHelper::~ScopedPerfEventHelper()
141 {
142 if (DebugAnnotationsActive())
143 {
144 g_debugAnnotator->endEvent(mFunctionName);
145 }
146 }
147
LogMessage(const char * function,int line,LogSeverity severity)148 LogMessage::LogMessage(const char *function, int line, LogSeverity severity)
149 : mFunction(function), mLine(line), mSeverity(severity)
150 {
151 // EVENT() does not require additional function(line) info.
152 if (mSeverity != LOG_EVENT)
153 {
154 mStream << mFunction << "(" << mLine << "): ";
155 }
156 }
157
~LogMessage()158 LogMessage::~LogMessage()
159 {
160 std::unique_lock<std::mutex> lock;
161 if (g_debugMutex != nullptr)
162 {
163 lock = std::unique_lock<std::mutex>(*g_debugMutex);
164 }
165
166 if (DebugAnnotationsInitialized() && (mSeverity >= LOG_INFO))
167 {
168 g_debugAnnotator->logMessage(*this);
169 }
170 else
171 {
172 Trace(getSeverity(), getMessage().c_str());
173 }
174
175 if (mSeverity == LOG_FATAL)
176 {
177 if (angle::IsDebuggerAttached())
178 {
179 angle::BreakDebugger();
180 }
181 else
182 {
183 ANGLE_CRASH();
184 }
185 }
186 }
187
Trace(LogSeverity severity,const char * message)188 void Trace(LogSeverity severity, const char *message)
189 {
190 if (!ShouldCreateLogMessage(severity))
191 {
192 return;
193 }
194
195 std::string str(message);
196
197 if (DebugAnnotationsActive())
198 {
199
200 switch (severity)
201 {
202 case LOG_EVENT:
203 // Debugging logging done in ScopedPerfEventHelper
204 break;
205 default:
206 g_debugAnnotator->setMarker(message);
207 break;
208 }
209 }
210
211 if (severity == LOG_FATAL || severity == LOG_ERR || severity == LOG_WARN ||
212 severity == LOG_INFO)
213 {
214 #if defined(ANGLE_PLATFORM_ANDROID)
215 android_LogPriority android_priority = ANDROID_LOG_ERROR;
216 switch (severity)
217 {
218 case LOG_INFO:
219 android_priority = ANDROID_LOG_INFO;
220 break;
221 case LOG_WARN:
222 android_priority = ANDROID_LOG_WARN;
223 break;
224 case LOG_ERR:
225 android_priority = ANDROID_LOG_ERROR;
226 break;
227 case LOG_FATAL:
228 android_priority = ANDROID_LOG_FATAL;
229 break;
230 default:
231 UNREACHABLE();
232 }
233 __android_log_print(android_priority, "ANGLE", "%s: %s\n", LogSeverityName(severity),
234 str.c_str());
235 #elif defined(ANGLE_PLATFORM_APPLE)
236 if (__builtin_available(macOS 10.12, iOS 10.0, *))
237 {
238 os_log_type_t apple_log_type = OS_LOG_TYPE_DEFAULT;
239 switch (severity)
240 {
241 case LOG_INFO:
242 apple_log_type = OS_LOG_TYPE_INFO;
243 break;
244 case LOG_WARN:
245 apple_log_type = OS_LOG_TYPE_DEFAULT;
246 break;
247 case LOG_ERR:
248 apple_log_type = OS_LOG_TYPE_ERROR;
249 break;
250 case LOG_FATAL:
251 // OS_LOG_TYPE_FAULT is too severe - grabs the entire process tree.
252 apple_log_type = OS_LOG_TYPE_ERROR;
253 break;
254 default:
255 UNREACHABLE();
256 }
257 os_log_with_type(OS_LOG_DEFAULT, apple_log_type, "ANGLE: %s: %s\n",
258 LogSeverityName(severity), str.c_str());
259 }
260 #else
261 // Note: we use fprintf because <iostream> includes static initializers.
262 fprintf((severity >= LOG_ERR) ? stderr : stdout, "%s: %s\n", LogSeverityName(severity),
263 str.c_str());
264 #endif
265 }
266
267 #if defined(ANGLE_PLATFORM_WINDOWS) && \
268 (defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) || !defined(NDEBUG))
269 # if !defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
270 if (severity >= LOG_ERR)
271 # endif // !defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
272 {
273 OutputDebugStringA(str.c_str());
274 }
275 #endif
276
277 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
278 # if defined(NDEBUG)
279 if (severity == LOG_EVENT || severity == LOG_WARN || severity == LOG_INFO)
280 {
281 return;
282 }
283 # endif // defined(NDEBUG)
284 static angle::base::NoDestructor<std::ofstream> file(TRACE_OUTPUT_FILE, std::ofstream::app);
285 if (file->good())
286 {
287 if (severity > LOG_EVENT)
288 {
289 *file << LogSeverityName(severity) << ": ";
290 }
291 *file << str << "\n";
292 file->flush();
293 }
294 #endif // defined(ANGLE_ENABLE_DEBUG_TRACE)
295 }
296
getSeverity() const297 LogSeverity LogMessage::getSeverity() const
298 {
299 return mSeverity;
300 }
301
getMessage() const302 std::string LogMessage::getMessage() const
303 {
304 return mStream.str();
305 }
306
307 #if defined(ANGLE_PLATFORM_WINDOWS)
FmtHR(HRESULT value)308 priv::FmtHexHelper<HRESULT> FmtHR(HRESULT value)
309 {
310 return priv::FmtHexHelper<HRESULT>("HRESULT: ", value);
311 }
312
FmtErr(DWORD value)313 priv::FmtHexHelper<DWORD> FmtErr(DWORD value)
314 {
315 return priv::FmtHexHelper<DWORD>("error: ", value);
316 }
317 #endif // defined(ANGLE_PLATFORM_WINDOWS)
318
319 } // namespace gl
320