1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BASE_LOGGING_H_ 6 #define THIRD_PARTY_BASE_LOGGING_H_ 7 8 #include <assert.h> 9 #include <stdlib.h> 10 11 #include "build/build_config.h" 12 #include "third_party/base/compiler_specific.h" 13 14 #if defined(COMPILER_GCC) 15 16 #if defined(ARCH_CPU_X86_FAMILY) 17 // int 3 will generate a SIGTRAP. 18 #define TRAP_SEQUENCE() \ 19 asm volatile( \ 20 "int3; ud2; push %0;" ::"i"(static_cast<unsigned char>(__COUNTER__))) 21 22 #elif defined(ARCH_CPU_ARMEL) 23 // bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running 24 // as a 32 bit userspace app on arm64. There doesn't seem to be any way to 25 // cause a SIGTRAP from userspace without using a syscall (which would be a 26 // problem for sandboxing). 27 #define TRAP_SEQUENCE() \ 28 asm volatile("bkpt #0; udf %0;" ::"i"(__COUNTER__ % 256)) 29 30 #elif defined(ARCH_CPU_ARM64) 31 // This will always generate a SIGTRAP on arm64. 32 #define TRAP_SEQUENCE() \ 33 asm volatile("brk #0; hlt %0;" ::"i"(__COUNTER__ % 65536)) 34 35 #else 36 // Crash report accuracy will not be guaranteed on other architectures, but at 37 // least this will crash as expected. 38 #define TRAP_SEQUENCE() __builtin_trap() 39 #endif // ARCH_CPU_* 40 41 #elif defined(COMPILER_MSVC) 42 43 // Clang is cleverer about coalescing int3s, so we need to add a unique-ish 44 // instruction following the __debugbreak() to have it emit distinct locations 45 // for CHECKs rather than collapsing them all together. It would be nice to use 46 // a short intrinsic to do this (and perhaps have only one implementation for 47 // both clang and MSVC), however clang-cl currently does not support intrinsics. 48 // On the flip side, MSVC x64 doesn't support inline asm. So, we have to have 49 // two implementations. Normally clang-cl's version will be 5 bytes (1 for 50 // `int3`, 2 for `ud2`, 2 for `push byte imm`, however, TODO(scottmg): 51 // https://crbug.com/694670 clang-cl doesn't currently support %'ing 52 // __COUNTER__, so eventually it will emit the dword form of push. 53 // TODO(scottmg): Reinvestigate a short sequence that will work on both 54 // compilers once clang supports more intrinsics. See https://crbug.com/693713. 55 #if !defined(__clang__) 56 #define TRAP_SEQUENCE() __debugbreak() 57 #elif defined(ARCH_CPU_ARM64) 58 #define TRAP_SEQUENCE() \ 59 __asm volatile("brk #0\n hlt %0\n" ::"i"(__COUNTER__ % 65536)); 60 #else 61 #define TRAP_SEQUENCE() ({ {__asm int 3 __asm ud2 __asm push __COUNTER__}; }) 62 #endif // __clang__ 63 64 #else 65 #error Port 66 #endif // COMPILER_GCC 67 68 // CHECK() and the trap sequence can be invoked from a constexpr function. 69 // This could make compilation fail on GCC, as it forbids directly using inline 70 // asm inside a constexpr function. However, it allows calling a lambda 71 // expression including the same asm. 72 // The side effect is that the top of the stacktrace will not point to the 73 // calling function, but to this anonymous lambda. This is still useful as the 74 // full name of the lambda will typically include the name of the function that 75 // calls CHECK() and the debugger will still break at the right line of code. 76 #if !defined(COMPILER_GCC) 77 #define WRAPPED_TRAP_SEQUENCE() TRAP_SEQUENCE() 78 #else 79 #define WRAPPED_TRAP_SEQUENCE() \ 80 do { \ 81 [] { TRAP_SEQUENCE(); }(); \ 82 } while (false) 83 #endif 84 85 #if defined(__clang__) || defined(COMPILER_GCC) 86 #define IMMEDIATE_CRASH() \ 87 ({ \ 88 WRAPPED_TRAP_SEQUENCE(); \ 89 __builtin_unreachable(); \ 90 }) 91 #else 92 // This is supporting non-chromium user of logging.h to build with MSVC, like 93 // pdfium. On MSVC there is no __builtin_unreachable(). 94 #define IMMEDIATE_CRASH() WRAPPED_TRAP_SEQUENCE() 95 #endif 96 97 #define CHECK(condition) \ 98 do { \ 99 if (UNLIKELY(!(condition))) { \ 100 IMMEDIATE_CRASH(); \ 101 } \ 102 } while (0) 103 104 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) 105 #define DCHECK_IS_ON() 0 106 #else 107 #define DCHECK_IS_ON() 1 108 #endif 109 110 // Debug mode: Use assert() for better diagnostics 111 // Release mode, DCHECK_ALWAYS_ON: Use CHECK() since assert() is a no-op. 112 // Release mode, no DCHECK_ALWAYS_ON: Use assert(), which is a no-op. 113 #if defined(NDEBUG) && defined(DCHECK_ALWAYS_ON) 114 #define DCHECK CHECK 115 #else 116 #define DCHECK assert 117 #endif 118 119 #define CHECK_EQ(x, y) CHECK((x) == (y)) 120 #define CHECK_NE(x, y) CHECK((x) != (y)) 121 #define DCHECK_EQ(x, y) DCHECK((x) == (y)) 122 #define DCHECK_NE(x, y) DCHECK((x) != (y)) 123 #define NOTREACHED() DCHECK(false) 124 125 #endif // THIRD_PARTY_BASE_LOGGING_H_ 126