| // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BASE_LOGGING_H_ |
| #define THIRD_PARTY_BASE_LOGGING_H_ |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| |
| #include "build/build_config.h" |
| #include "third_party/base/compiler_specific.h" |
| |
| #if defined(COMPILER_GCC) |
| |
| #if defined(ARCH_CPU_X86_FAMILY) |
| // int 3 will generate a SIGTRAP. |
| #define TRAP_SEQUENCE() \ |
| asm volatile( \ |
| "int3; ud2; push %0;" ::"i"(static_cast<unsigned char>(__COUNTER__))) |
| |
| #elif defined(ARCH_CPU_ARMEL) |
| // bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running |
| // as a 32 bit userspace app on arm64. There doesn't seem to be any way to |
| // cause a SIGTRAP from userspace without using a syscall (which would be a |
| // problem for sandboxing). |
| #define TRAP_SEQUENCE() \ |
| asm volatile("bkpt #0; udf %0;" ::"i"(__COUNTER__ % 256)) |
| |
| #elif defined(ARCH_CPU_ARM64) |
| // This will always generate a SIGTRAP on arm64. |
| #define TRAP_SEQUENCE() \ |
| asm volatile("brk #0; hlt %0;" ::"i"(__COUNTER__ % 65536)) |
| |
| #else |
| // Crash report accuracy will not be guaranteed on other architectures, but at |
| // least this will crash as expected. |
| #define TRAP_SEQUENCE() __builtin_trap() |
| #endif // ARCH_CPU_* |
| |
| #elif defined(COMPILER_MSVC) |
| |
| // Clang is cleverer about coalescing int3s, so we need to add a unique-ish |
| // instruction following the __debugbreak() to have it emit distinct locations |
| // for CHECKs rather than collapsing them all together. It would be nice to use |
| // a short intrinsic to do this (and perhaps have only one implementation for |
| // both clang and MSVC), however clang-cl currently does not support intrinsics. |
| // On the flip side, MSVC x64 doesn't support inline asm. So, we have to have |
| // two implementations. Normally clang-cl's version will be 5 bytes (1 for |
| // `int3`, 2 for `ud2`, 2 for `push byte imm`, however, TODO(scottmg): |
| // https://crbug.com/694670 clang-cl doesn't currently support %'ing |
| // __COUNTER__, so eventually it will emit the dword form of push. |
| // TODO(scottmg): Reinvestigate a short sequence that will work on both |
| // compilers once clang supports more intrinsics. See https://crbug.com/693713. |
| #if !defined(__clang__) |
| #define TRAP_SEQUENCE() __debugbreak() |
| #elif defined(ARCH_CPU_ARM64) |
| #define TRAP_SEQUENCE() \ |
| __asm volatile("brk #0\n hlt %0\n" ::"i"(__COUNTER__ % 65536)); |
| #else |
| #define TRAP_SEQUENCE() ({ {__asm int 3 __asm ud2 __asm push __COUNTER__}; }) |
| #endif // __clang__ |
| |
| #else |
| #error Port |
| #endif // COMPILER_GCC |
| |
| // CHECK() and the trap sequence can be invoked from a constexpr function. |
| // This could make compilation fail on GCC, as it forbids directly using inline |
| // asm inside a constexpr function. However, it allows calling a lambda |
| // expression including the same asm. |
| // The side effect is that the top of the stacktrace will not point to the |
| // calling function, but to this anonymous lambda. This is still useful as the |
| // full name of the lambda will typically include the name of the function that |
| // calls CHECK() and the debugger will still break at the right line of code. |
| #if !defined(COMPILER_GCC) |
| #define WRAPPED_TRAP_SEQUENCE() TRAP_SEQUENCE() |
| #else |
| #define WRAPPED_TRAP_SEQUENCE() \ |
| do { \ |
| [] { TRAP_SEQUENCE(); }(); \ |
| } while (false) |
| #endif |
| |
| #if defined(__clang__) || defined(COMPILER_GCC) |
| #define IMMEDIATE_CRASH() \ |
| ({ \ |
| WRAPPED_TRAP_SEQUENCE(); \ |
| __builtin_unreachable(); \ |
| }) |
| #else |
| // This is supporting non-chromium user of logging.h to build with MSVC, like |
| // pdfium. On MSVC there is no __builtin_unreachable(). |
| #define IMMEDIATE_CRASH() WRAPPED_TRAP_SEQUENCE() |
| #endif |
| |
| #define CHECK(condition) \ |
| do { \ |
| if (UNLIKELY(!(condition))) { \ |
| IMMEDIATE_CRASH(); \ |
| } \ |
| } while (0) |
| |
| #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) |
| #define DCHECK_IS_ON() 0 |
| #else |
| #define DCHECK_IS_ON() 1 |
| #endif |
| |
| // Debug mode: Use assert() for better diagnostics |
| // Release mode, DCHECK_ALWAYS_ON: Use CHECK() since assert() is a no-op. |
| // Release mode, no DCHECK_ALWAYS_ON: Use assert(), which is a no-op. |
| #if defined(NDEBUG) && defined(DCHECK_ALWAYS_ON) |
| #define DCHECK CHECK |
| #else |
| #define DCHECK assert |
| #endif |
| |
| #define DCHECK_EQ(x, y) DCHECK((x) == (y)) |
| #define NOTREACHED() DCHECK(false) |
| |
| #endif // THIRD_PARTY_BASE_LOGGING_H_ |