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