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