• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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