immediate_crash.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright 2021 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. // This file is copied from //base/immediate_crash.h.
  5. #ifndef BUILD_RUST_STD_IMMEDIATE_CRASH_H_
  6. #define BUILD_RUST_STD_IMMEDIATE_CRASH_H_
  7. #include "build/build_config.h"
  8. // Crashes in the fastest possible way with no attempt at logging.
  9. // There are several constraints; see http://crbug.com/664209 for more context.
  10. //
  11. // - TRAP_SEQUENCE_() must be fatal. It should not be possible to ignore the
  12. // resulting exception or simply hit 'continue' to skip over it in a debugger.
  13. // - Different instances of TRAP_SEQUENCE_() must not be folded together, to
  14. // ensure crash reports are debuggable. Unlike __builtin_trap(), asm volatile
  15. // blocks will not be folded together.
  16. // Note: TRAP_SEQUENCE_() previously required an instruction with a unique
  17. // nonce since unlike clang, GCC folds together identical asm volatile
  18. // blocks.
  19. // - TRAP_SEQUENCE_() must produce a signal that is distinct from an invalid
  20. // memory access.
  21. // - TRAP_SEQUENCE_() must be treated as a set of noreturn instructions.
  22. // __builtin_unreachable() is used to provide that hint here. clang also uses
  23. // this as a heuristic to pack the instructions in the function epilogue to
  24. // improve code density.
  25. //
  26. // Additional properties that are nice to have:
  27. // - TRAP_SEQUENCE_() should be as compact as possible.
  28. // - The first instruction of TRAP_SEQUENCE_() should not change, to avoid
  29. // shifting crash reporting clusters. As a consequence of this, explicit
  30. // assembly is preferred over intrinsics.
  31. // Note: this last bullet point may no longer be true, and may be removed in
  32. // the future.
  33. // Note: TRAP_SEQUENCE Is currently split into two macro helpers due to the fact
  34. // that clang emits an actual instruction for __builtin_unreachable() on certain
  35. // platforms (see https://crbug.com/958675). In addition, the int3/bkpt/brk will
  36. // be removed in followups, so splitting it up like this now makes it easy to
  37. // land the followups.
  38. #if defined(COMPILER_GCC)
  39. #if BUILDFLAG(IS_NACL)
  40. // Crash report accuracy is not guaranteed on NaCl.
  41. #define TRAP_SEQUENCE1_() __builtin_trap()
  42. #define TRAP_SEQUENCE2_() asm volatile("")
  43. #elif defined(ARCH_CPU_X86_FAMILY)
  44. // TODO(https://crbug.com/958675): In theory, it should be possible to use just
  45. // int3. However, there are a number of crashes with SIGILL as the exception
  46. // code, so it seems likely that there's a signal handler that allows execution
  47. // to continue after SIGTRAP.
  48. #define TRAP_SEQUENCE1_() asm volatile("int3")
  49. #if BUILDFLAG(IS_APPLE)
  50. // Intentionally empty: __builtin_unreachable() is always part of the sequence
  51. // (see IMMEDIATE_CRASH below) and already emits a ud2 on Mac.
  52. #define TRAP_SEQUENCE2_() asm volatile("")
  53. #else
  54. #define TRAP_SEQUENCE2_() asm volatile("ud2")
  55. #endif // BUILDFLAG(IS_APPLE)
  56. #elif defined(ARCH_CPU_ARMEL)
  57. // bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running
  58. // as a 32 bit userspace app on arm64. There doesn't seem to be any way to
  59. // cause a SIGTRAP from userspace without using a syscall (which would be a
  60. // problem for sandboxing).
  61. // TODO(https://crbug.com/958675): Remove bkpt from this sequence.
  62. #define TRAP_SEQUENCE1_() asm volatile("bkpt #0")
  63. #define TRAP_SEQUENCE2_() asm volatile("udf #0")
  64. #elif defined(ARCH_CPU_ARM64)
  65. // This will always generate a SIGTRAP on arm64.
  66. // TODO(https://crbug.com/958675): Remove brk from this sequence.
  67. #define TRAP_SEQUENCE1_() asm volatile("brk #0")
  68. #define TRAP_SEQUENCE2_() asm volatile("hlt #0")
  69. #else
  70. // Crash report accuracy will not be guaranteed on other architectures, but at
  71. // least this will crash as expected.
  72. #define TRAP_SEQUENCE1_() __builtin_trap()
  73. #define TRAP_SEQUENCE2_() asm volatile("")
  74. #endif // ARCH_CPU_*
  75. #elif defined(COMPILER_MSVC)
  76. #if !defined(__clang__)
  77. // MSVC x64 doesn't support inline asm, so use the MSVC intrinsic.
  78. #define TRAP_SEQUENCE1_() __debugbreak()
  79. #define TRAP_SEQUENCE2_()
  80. #elif defined(ARCH_CPU_ARM64)
  81. // Windows ARM64 uses "BRK #F000" as its breakpoint instruction, and
  82. // __debugbreak() generates that in both VC++ and clang.
  83. #define TRAP_SEQUENCE1_() __debugbreak()
  84. // Intentionally empty: __builtin_unreachable() is always part of the sequence
  85. // (see IMMEDIATE_CRASH below) and already emits a ud2 on Win64,
  86. // https://crbug.com/958373
  87. #define TRAP_SEQUENCE2_() __asm volatile("")
  88. #else
  89. #define TRAP_SEQUENCE1_() asm volatile("int3")
  90. #define TRAP_SEQUENCE2_() asm volatile("ud2")
  91. #endif // __clang__
  92. #else
  93. #error No supported trap sequence!
  94. #endif // COMPILER_GCC
  95. #define TRAP_SEQUENCE_() \
  96. do { \
  97. TRAP_SEQUENCE1_(); \
  98. TRAP_SEQUENCE2_(); \
  99. } while (false)
  100. // CHECK() and the trap sequence can be invoked from a constexpr function.
  101. // This could make compilation fail on GCC, as it forbids directly using inline
  102. // asm inside a constexpr function. However, it allows calling a lambda
  103. // expression including the same asm.
  104. // The side effect is that the top of the stacktrace will not point to the
  105. // calling function, but to this anonymous lambda. This is still useful as the
  106. // full name of the lambda will typically include the name of the function that
  107. // calls CHECK() and the debugger will still break at the right line of code.
  108. #if !defined(COMPILER_GCC) || defined(__clang__)
  109. #define WRAPPED_TRAP_SEQUENCE_() TRAP_SEQUENCE_()
  110. #else
  111. #define WRAPPED_TRAP_SEQUENCE_() \
  112. do { \
  113. [] { TRAP_SEQUENCE_(); }(); \
  114. } while (false)
  115. #endif // !defined(COMPILER_GCC) || defined(__clang__)
  116. #if defined(__clang__) || defined(COMPILER_GCC)
  117. // __builtin_unreachable() hints to the compiler that this is noreturn and can
  118. // be packed in the function epilogue.
  119. #define IMMEDIATE_CRASH() \
  120. ({ \
  121. WRAPPED_TRAP_SEQUENCE_(); \
  122. __builtin_unreachable(); \
  123. })
  124. #else
  125. // This is supporting non-chromium user of logging.h to build with MSVC, like
  126. // pdfium. On MSVC there is no __builtin_unreachable().
  127. #define IMMEDIATE_CRASH() WRAPPED_TRAP_SEQUENCE_()
  128. #endif // defined(__clang__) || defined(COMPILER_GCC)
  129. #endif // BUILD_RUST_STD_IMMEDIATE_CRASH_H_