tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

debug.h (19473B)


      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.h: Debugging utilities. A lot of the logging code is adapted from Chromium's
      8 // base/logging.h.
      9 
     10 #ifndef COMMON_DEBUG_H_
     11 #define COMMON_DEBUG_H_
     12 
     13 #include <assert.h>
     14 #include <stdio.h>
     15 
     16 #include <iomanip>
     17 #include <ios>
     18 #include <mutex>
     19 #include <sstream>
     20 #include <string>
     21 
     22 #include "common/angleutils.h"
     23 #include "common/entry_points_enum_autogen.h"
     24 #include "common/platform.h"
     25 
     26 #if defined(ANGLE_PLATFORM_WINDOWS)
     27 #    include <sal.h>
     28 typedef unsigned long DWORD;
     29 typedef _Return_type_success_(return >= 0) long HRESULT;
     30 #endif
     31 
     32 #if !defined(TRACE_OUTPUT_FILE)
     33 #    define TRACE_OUTPUT_FILE "angle_debug.txt"
     34 #endif
     35 
     36 namespace gl
     37 {
     38 class Context;
     39 
     40 // Pairs a begin event with an end event.
     41 class [[nodiscard]] ScopedPerfEventHelper : angle::NonCopyable
     42 {
     43  public:
     44    ScopedPerfEventHelper(Context *context, angle::EntryPoint entryPoint);
     45    ~ScopedPerfEventHelper();
     46    ANGLE_FORMAT_PRINTF(2, 3)
     47    void begin(const char *format, ...);
     48 
     49  private:
     50    gl::Context *mContext;
     51    const angle::EntryPoint mEntryPoint;
     52    const char *mFunctionName;
     53    bool mCalledBeginEvent;
     54 };
     55 
     56 using LogSeverity = int;
     57 // Note: the log severities are used to index into the array of names,
     58 // see g_logSeverityNames.
     59 constexpr LogSeverity LOG_EVENT          = 0;
     60 constexpr LogSeverity LOG_INFO           = 1;
     61 constexpr LogSeverity LOG_WARN           = 2;
     62 constexpr LogSeverity LOG_ERR            = 3;
     63 constexpr LogSeverity LOG_FATAL          = 4;
     64 constexpr LogSeverity LOG_NUM_SEVERITIES = 5;
     65 
     66 void Trace(LogSeverity severity, const char *message);
     67 
     68 // This class more or less represents a particular log message.  You
     69 // create an instance of LogMessage and then stream stuff to it.
     70 // When you finish streaming to it, ~LogMessage is called and the
     71 // full message gets streamed to the appropriate destination.
     72 //
     73 // You shouldn't actually use LogMessage's constructor to log things,
     74 // though.  You should use the ERR() and WARN() macros.
     75 class LogMessage : angle::NonCopyable
     76 {
     77  public:
     78    // Used for ANGLE_LOG(severity).
     79    LogMessage(const char *file, const char *function, int line, LogSeverity severity);
     80    ~LogMessage();
     81    std::ostream &stream() { return mStream; }
     82 
     83    LogSeverity getSeverity() const;
     84    std::string getMessage() const;
     85 
     86  private:
     87    const char *mFile;
     88    const char *mFunction;
     89    const int mLine;
     90    const LogSeverity mSeverity;
     91 
     92    std::ostringstream mStream;
     93 };
     94 
     95 // Wraps the API/Platform-specific debug annotation functions.
     96 // Also handles redirecting logging destination.
     97 class DebugAnnotator : angle::NonCopyable
     98 {
     99  public:
    100    DebugAnnotator() {}
    101    virtual ~DebugAnnotator() {}
    102    virtual void beginEvent(gl::Context *context,
    103                            angle::EntryPoint entryPoint,
    104                            const char *eventName,
    105                            const char *eventMessage)                    = 0;
    106    virtual void endEvent(gl::Context *context,
    107                          const char *eventName,
    108                          angle::EntryPoint entryPoint)                  = 0;
    109    virtual void setMarker(gl::Context *context, const char *markerName) = 0;
    110    virtual bool getStatus(const gl::Context *context)                   = 0;
    111    // Log Message Handler that gets passed every log message,
    112    // when debug annotations are initialized,
    113    // replacing default handling by LogMessage.
    114    virtual void logMessage(const LogMessage &msg) const = 0;
    115 };
    116 
    117 bool ShouldBeginScopedEvent(const gl::Context *context);
    118 void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator);
    119 void UninitializeDebugAnnotations();
    120 bool DebugAnnotationsActive(const gl::Context *context);
    121 bool DebugAnnotationsInitialized();
    122 
    123 void InitializeDebugMutexIfNeeded();
    124 
    125 std::mutex &GetDebugMutex();
    126 
    127 namespace priv
    128 {
    129 // This class is used to explicitly ignore values in the conditional logging macros. This avoids
    130 // compiler warnings like "value computed is not used" and "statement has no effect".
    131 class LogMessageVoidify
    132 {
    133  public:
    134    LogMessageVoidify() {}
    135    // This has to be an operator with a precedence lower than << but higher than ?:
    136    void operator&(std::ostream &) {}
    137 };
    138 
    139 extern std::ostream *gSwallowStream;
    140 
    141 // Used by ANGLE_LOG_IS_ON to lazy-evaluate stream arguments.
    142 bool ShouldCreatePlatformLogMessage(LogSeverity severity);
    143 
    144 // N is the width of the output to the stream. The output is padded with zeros
    145 // if value is less than N characters.
    146 // S is the stream type, either ostream for ANSI or wostream for wide character.
    147 // T is the type of the value to output to the stream.
    148 // C is the type of characters - either char for ANSI or wchar_t for wide char.
    149 template <int N, typename S, typename T, typename C>
    150 S &FmtHex(S &stream, T value, const C *zeroX, C zero)
    151 {
    152    stream << zeroX;
    153 
    154    std::ios_base::fmtflags oldFlags = stream.flags();
    155    std::streamsize oldWidth         = stream.width();
    156    typename S::char_type oldFill    = stream.fill();
    157 
    158    stream << std::hex << std::uppercase << std::setw(N) << std::setfill(zero) << value;
    159 
    160    stream.flags(oldFlags);
    161    stream.width(oldWidth);
    162    stream.fill(oldFill);
    163 
    164    return stream;
    165 }
    166 
    167 template <typename S, typename T, typename C>
    168 S &FmtHexAutoSized(S &stream, T value, const C *prefix, const C *zeroX, C zero)
    169 {
    170    if (prefix)
    171    {
    172        stream << prefix;
    173    }
    174 
    175    constexpr int N = sizeof(T) * 2;
    176    return priv::FmtHex<N>(stream, value, zeroX, zero);
    177 }
    178 
    179 template <typename T, typename C>
    180 class FmtHexHelper
    181 {
    182  public:
    183    FmtHexHelper(const C *prefix, T value) : mPrefix(prefix), mValue(value) {}
    184    explicit FmtHexHelper(T value) : mPrefix(nullptr), mValue(value) {}
    185 
    186  private:
    187    const C *mPrefix;
    188    T mValue;
    189 
    190    friend std::ostream &operator<<(std::ostream &os, const FmtHexHelper &fmt)
    191    {
    192        return FmtHexAutoSized(os, fmt.mValue, fmt.mPrefix, "0x", '0');
    193    }
    194 
    195    friend std::wostream &operator<<(std::wostream &wos, const FmtHexHelper &fmt)
    196    {
    197        return FmtHexAutoSized(wos, fmt.mValue, fmt.mPrefix, L"0x", L'0');
    198    }
    199 };
    200 
    201 }  // namespace priv
    202 
    203 template <typename T, typename C = char>
    204 priv::FmtHexHelper<T, C> FmtHex(T value)
    205 {
    206    return priv::FmtHexHelper<T, C>(value);
    207 }
    208 
    209 #if defined(ANGLE_PLATFORM_WINDOWS)
    210 priv::FmtHexHelper<HRESULT, char> FmtHR(HRESULT value);
    211 priv::FmtHexHelper<DWORD, char> FmtErr(DWORD value);
    212 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
    213 
    214 template <typename T>
    215 std::ostream &FmtHex(std::ostream &os, T value)
    216 {
    217    return priv::FmtHexAutoSized(os, value, "", "0x", '0');
    218 }
    219 
    220 // A few definitions of macros that don't generate much code. These are used
    221 // by ANGLE_LOG(). Since these are used all over our code, it's
    222 // better to have compact code for these operations.
    223 #define COMPACT_ANGLE_LOG_EX_EVENT(ClassName, ...) \
    224    ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_EVENT, ##__VA_ARGS__)
    225 #define COMPACT_ANGLE_LOG_EX_INFO(ClassName, ...) \
    226    ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_INFO, ##__VA_ARGS__)
    227 #define COMPACT_ANGLE_LOG_EX_WARN(ClassName, ...) \
    228    ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_WARN, ##__VA_ARGS__)
    229 #define COMPACT_ANGLE_LOG_EX_ERR(ClassName, ...) \
    230    ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_ERR, ##__VA_ARGS__)
    231 #define COMPACT_ANGLE_LOG_EX_FATAL(ClassName, ...) \
    232    ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_FATAL, ##__VA_ARGS__)
    233 
    234 #define COMPACT_ANGLE_LOG_EVENT COMPACT_ANGLE_LOG_EX_EVENT(LogMessage)
    235 #define COMPACT_ANGLE_LOG_INFO COMPACT_ANGLE_LOG_EX_INFO(LogMessage)
    236 #define COMPACT_ANGLE_LOG_WARN COMPACT_ANGLE_LOG_EX_WARN(LogMessage)
    237 #define COMPACT_ANGLE_LOG_ERR COMPACT_ANGLE_LOG_EX_ERR(LogMessage)
    238 #define COMPACT_ANGLE_LOG_FATAL COMPACT_ANGLE_LOG_EX_FATAL(LogMessage)
    239 
    240 #define ANGLE_LOG_IS_ON(severity) (::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_##severity))
    241 
    242 // Helper macro which avoids evaluating the arguments to a stream if the condition doesn't hold.
    243 // Condition is evaluated once and only once.
    244 #define ANGLE_LAZY_STREAM(stream, condition) \
    245    !(condition) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (stream)
    246 
    247 // We use the preprocessor's merging operator, "##", so that, e.g.,
    248 // ANGLE_LOG(EVENT) becomes the token COMPACT_ANGLE_LOG_EVENT.  There's some funny
    249 // subtle difference between ostream member streaming functions (e.g.,
    250 // ostream::operator<<(int) and ostream non-member streaming functions
    251 // (e.g., ::operator<<(ostream&, string&): it turns out that it's
    252 // impossible to stream something like a string directly to an unnamed
    253 // ostream. We employ a neat hack by calling the stream() member
    254 // function of LogMessage which seems to avoid the problem.
    255 #define ANGLE_LOG_STREAM(severity) COMPACT_ANGLE_LOG_##severity.stream()
    256 
    257 #define ANGLE_LOG(severity) ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(severity), ANGLE_LOG_IS_ON(severity))
    258 
    259 }  // namespace gl
    260 
    261 #if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
    262 #    define ANGLE_TRACE_ENABLED
    263 #endif
    264 
    265 #if !defined(NDEBUG) || defined(ANGLE_ASSERT_ALWAYS_ON)
    266 #    define ANGLE_ENABLE_ASSERTS
    267 #endif
    268 
    269 #define INFO() ANGLE_LOG(INFO)
    270 #define WARN() ANGLE_LOG(WARN)
    271 #define ERR() ANGLE_LOG(ERR)
    272 #define FATAL() ANGLE_LOG(FATAL)
    273 
    274 // A macro to log a performance event around a scope.
    275 #if defined(ANGLE_TRACE_ENABLED)
    276 #    if defined(_MSC_VER)
    277 #        define EVENT(context, entryPoint, message, ...)                                     \
    278            gl::ScopedPerfEventHelper scopedPerfEventHelper##__LINE__(                       \
    279                context, angle::EntryPoint::entryPoint);                                     \
    280            do                                                                               \
    281            {                                                                                \
    282                if (gl::ShouldBeginScopedEvent(context))                                     \
    283                {                                                                            \
    284                    scopedPerfEventHelper##__LINE__.begin(                                   \
    285                        "%s(" message ")", GetEntryPointName(angle::EntryPoint::entryPoint), \
    286                        __VA_ARGS__);                                                        \
    287                }                                                                            \
    288            } while (0)
    289 #    else
    290 #        define EVENT(context, entryPoint, message, ...)                                          \
    291            gl::ScopedPerfEventHelper scopedPerfEventHelper(context,                              \
    292                                                            angle::EntryPoint::entryPoint);       \
    293            do                                                                                    \
    294            {                                                                                     \
    295                if (gl::ShouldBeginScopedEvent(context))                                          \
    296                {                                                                                 \
    297                    scopedPerfEventHelper.begin("%s(" message ")",                                \
    298                                                GetEntryPointName(angle::EntryPoint::entryPoint), \
    299                                                ##__VA_ARGS__);                                   \
    300                }                                                                                 \
    301            } while (0)
    302 #    endif  // _MSC_VER
    303 #else
    304 #    define EVENT(message, ...) (void(0))
    305 #endif
    306 
    307 // The state tracked by ANGLE will be validated with the driver state before each call
    308 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
    309 #    define ANGLE_STATE_VALIDATION_ENABLED
    310 #endif
    311 
    312 #if defined(__GNUC__)
    313 #    define ANGLE_CRASH() __builtin_trap()
    314 #else
    315 #    define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0)), __assume(0)
    316 #endif
    317 
    318 #if !defined(NDEBUG)
    319 #    define ANGLE_ASSERT_IMPL(expression) assert(expression)
    320 #else
    321 // TODO(jmadill): Detect if debugger is attached and break.
    322 #    define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH()
    323 #endif  // !defined(NDEBUG)
    324 
    325 // Note that gSwallowStream is used instead of an arbitrary LOG() stream to avoid the creation of an
    326 // object with a non-trivial destructor (LogMessage). On MSVC x86 (checked on 2015 Update 3), this
    327 // causes a few additional pointless instructions to be emitted even at full optimization level,
    328 // even though the : arm of the ternary operator is clearly never executed. Using a simpler object
    329 // to be &'d with Voidify() avoids these extra instructions. Using a simpler POD object with a
    330 // templated operator<< also works to avoid these instructions. However, this causes warnings on
    331 // statically defined implementations of operator<<(std::ostream, ...) in some .cpp files, because
    332 // they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an ostream* also is
    333 // not suitable, because some compilers warn of undefined behavior.
    334 #define ANGLE_EAT_STREAM_PARAMETERS \
    335    true ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (*::gl::priv::gSwallowStream)
    336 
    337 // A macro asserting a condition and outputting failures to the debug log
    338 #if defined(ANGLE_ENABLE_ASSERTS)
    339 #    define ASSERT(expression)                                                                \
    340        (expression ? static_cast<void>(0)                                                    \
    341                    : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \
    342                               << ":" << __LINE__ << "): " << #expression))
    343 #else
    344 #    define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
    345 #endif  // defined(ANGLE_ENABLE_ASSERTS)
    346 
    347 #define ANGLE_UNUSED_VARIABLE(variable) (static_cast<void>(variable))
    348 
    349 // A macro to indicate unimplemented functionality
    350 #ifndef NOASSERT_UNIMPLEMENTED
    351 #    define NOASSERT_UNIMPLEMENTED 1
    352 #endif
    353 
    354 #if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
    355 #    define UNIMPLEMENTED()                                                                       \
    356        do                                                                                        \
    357        {                                                                                         \
    358            WARN() << "\t! Unimplemented: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \
    359                   << ")";                                                                        \
    360            ASSERT(NOASSERT_UNIMPLEMENTED);                                                       \
    361        } while (0)
    362 
    363 // A macro for code which is not expected to be reached under valid assumptions
    364 #    define UNREACHABLE()                                                                    \
    365        do                                                                                   \
    366        {                                                                                    \
    367            FATAL() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" \
    368                    << __LINE__ << ")";                                                      \
    369        } while (0)
    370 #else
    371 #    define UNIMPLEMENTED()                 \
    372        do                                  \
    373        {                                   \
    374            ASSERT(NOASSERT_UNIMPLEMENTED); \
    375        } while (0)
    376 
    377 // A macro for code which is not expected to be reached under valid assumptions
    378 #    define UNREACHABLE()  \
    379        do                 \
    380        {                  \
    381            ASSERT(false); \
    382        } while (0)
    383 #endif  // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
    384 
    385 #if defined(ANGLE_PLATFORM_WINDOWS)
    386 #    define ANGLE_FUNCTION __FUNCTION__
    387 #else
    388 #    define ANGLE_FUNCTION __func__
    389 #endif
    390 
    391 // Defining ANGLE_ENABLE_STRUCT_PADDING_WARNINGS will enable warnings when members are added to
    392 // structs to enforce packing. This is helpful for diagnosing unexpected struct sizes when making
    393 // fast cache variables.
    394 #if defined(__clang__)
    395 #    define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
    396        _Pragma("clang diagnostic push") _Pragma("clang diagnostic error \"-Wpadded\"")
    397 #    define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("clang diagnostic pop")
    398 #elif defined(__GNUC__)
    399 #    define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
    400        _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wpadded\"")
    401 #    define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("GCC diagnostic pop")
    402 #elif defined(_MSC_VER)
    403 #    define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
    404        __pragma(warning(push)) __pragma(warning(error : 4820))
    405 #    define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS __pragma(warning(pop))
    406 #else
    407 #    define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
    408 #    define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
    409 #endif
    410 
    411 #if defined(__clang__)
    412 #    define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS                               \
    413        _Pragma("clang diagnostic push")                                          \
    414            _Pragma("clang diagnostic ignored \"-Wsuggest-destructor-override\"") \
    415                _Pragma("clang diagnostic ignored \"-Wsuggest-override\"")
    416 #    define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS _Pragma("clang diagnostic pop")
    417 #else
    418 #    define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
    419 #    define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
    420 #endif
    421 
    422 #if defined(__clang__)
    423 #    define ANGLE_DISABLE_EXTRA_SEMI_WARNING \
    424        _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi\"")
    425 #    define ANGLE_REENABLE_EXTRA_SEMI_WARNING _Pragma("clang diagnostic pop")
    426 #else
    427 #    define ANGLE_DISABLE_EXTRA_SEMI_WARNING
    428 #    define ANGLE_REENABLE_EXTRA_SEMI_WARNING
    429 #endif
    430 
    431 #if defined(__clang__)
    432 #    define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING \
    433        _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi-stmt\"")
    434 #    define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING _Pragma("clang diagnostic pop")
    435 #else
    436 #    define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING
    437 #    define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING
    438 #endif
    439 
    440 #if defined(__clang__)
    441 #    define ANGLE_DISABLE_SHADOWING_WARNING \
    442        _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow-field\"")
    443 #    define ANGLE_REENABLE_SHADOWING_WARNING _Pragma("clang diagnostic pop")
    444 #else
    445 #    define ANGLE_DISABLE_SHADOWING_WARNING
    446 #    define ANGLE_REENABLE_SHADOWING_WARNING
    447 #endif
    448 
    449 #if defined(__clang__)
    450 #    define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING \
    451        _Pragma("clang diagnostic push")              \
    452            _Pragma("clang diagnostic ignored \"-Winconsistent-missing-destructor-override\"")
    453 #    define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING _Pragma("clang diagnostic pop")
    454 #else
    455 #    define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING
    456 #    define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING
    457 #endif
    458 
    459 #if defined(__clang__)
    460 #    define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING \
    461        _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-function\"")
    462 #    define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING _Pragma("clang diagnostic pop")
    463 #else
    464 #    define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING
    465 #    define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING
    466 #endif
    467 
    468 #endif  // COMMON_DEBUG_H_