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