You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
4.5 KiB
126 lines
4.5 KiB
// 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 CHECK_EQ(x, y) CHECK((x) == (y))
|
|
#define CHECK_NE(x, y) CHECK((x) != (y))
|
|
#define DCHECK_EQ(x, y) DCHECK((x) == (y))
|
|
#define DCHECK_NE(x, y) DCHECK((x) != (y))
|
|
#define NOTREACHED() DCHECK(false)
|
|
|
|
#endif // THIRD_PARTY_BASE_LOGGING_H_
|