scudo_utils.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. //===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// Platform specific utility functions.
  10. ///
  11. //===----------------------------------------------------------------------===//
  12. #include "scudo_utils.h"
  13. #if defined(__x86_64__) || defined(__i386__)
  14. # include <cpuid.h>
  15. #elif defined(__arm__) || defined(__aarch64__)
  16. # include "sanitizer_common/sanitizer_getauxval.h"
  17. # if SANITIZER_FUCHSIA
  18. # error #include <zircon/syscalls.h>
  19. # error #include <zircon/features.h>
  20. # elif SANITIZER_POSIX
  21. # include "sanitizer_common/sanitizer_posix.h"
  22. # include <fcntl.h>
  23. # endif
  24. #endif
  25. #include <stdarg.h>
  26. // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
  27. // complicated string formatting code. The following is a
  28. // temporary workaround to be able to use __sanitizer::VSNPrintf.
  29. namespace __sanitizer {
  30. extern int VSNPrintf(char *buff, int buff_length, const char *format,
  31. va_list args);
  32. } // namespace __sanitizer
  33. namespace __scudo {
  34. void dieWithMessage(const char *Format, ...) {
  35. static const char ScudoError[] = "Scudo ERROR: ";
  36. static constexpr uptr PrefixSize = sizeof(ScudoError) - 1;
  37. // Our messages are tiny, 256 characters is more than enough.
  38. char Message[256];
  39. va_list Args;
  40. va_start(Args, Format);
  41. internal_memcpy(Message, ScudoError, PrefixSize);
  42. VSNPrintf(Message + PrefixSize, sizeof(Message) - PrefixSize, Format, Args);
  43. va_end(Args);
  44. LogMessageOnPrintf(Message);
  45. if (common_flags()->abort_on_error)
  46. SetAbortMessage(Message);
  47. RawWrite(Message);
  48. Die();
  49. }
  50. #if defined(__x86_64__) || defined(__i386__)
  51. // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
  52. // CRC32 requires the SSE 4.2 instruction set.
  53. # ifndef bit_SSE4_2
  54. # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines.
  55. # endif
  56. #ifndef signature_HYGON_ebx // They are not defined in gcc.
  57. // HYGON: "HygonGenuine".
  58. #define signature_HYGON_ebx 0x6f677948
  59. #define signature_HYGON_edx 0x6e65476e
  60. #define signature_HYGON_ecx 0x656e6975
  61. #endif
  62. bool hasHardwareCRC32() {
  63. u32 Eax, Ebx, Ecx, Edx;
  64. __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx);
  65. const bool IsIntel = (Ebx == signature_INTEL_ebx) &&
  66. (Edx == signature_INTEL_edx) &&
  67. (Ecx == signature_INTEL_ecx);
  68. const bool IsAMD = (Ebx == signature_AMD_ebx) &&
  69. (Edx == signature_AMD_edx) &&
  70. (Ecx == signature_AMD_ecx);
  71. const bool IsHygon = (Ebx == signature_HYGON_ebx) &&
  72. (Edx == signature_HYGON_edx) &&
  73. (Ecx == signature_HYGON_ecx);
  74. if (!IsIntel && !IsAMD && !IsHygon)
  75. return false;
  76. __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx);
  77. return !!(Ecx & bit_SSE4_2);
  78. }
  79. #elif defined(__arm__) || defined(__aarch64__)
  80. // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP
  81. // auxiliary vector.
  82. # ifndef AT_HWCAP
  83. # define AT_HWCAP 16
  84. # endif
  85. # ifndef HWCAP_CRC32
  86. # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms.
  87. # endif
  88. # if SANITIZER_POSIX
  89. bool hasHardwareCRC32ARMPosix() {
  90. uptr F = internal_open("/proc/self/auxv", O_RDONLY);
  91. if (internal_iserror(F))
  92. return false;
  93. struct { uptr Tag; uptr Value; } Entry = { 0, 0 };
  94. for (;;) {
  95. uptr N = internal_read(F, &Entry, sizeof(Entry));
  96. if (internal_iserror(N) || N != sizeof(Entry) ||
  97. (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP)
  98. break;
  99. }
  100. internal_close(F);
  101. return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0);
  102. }
  103. # else
  104. bool hasHardwareCRC32ARMPosix() { return false; }
  105. # endif // SANITIZER_POSIX
  106. // Bionic doesn't initialize its globals early enough. This causes issues when
  107. // trying to access them from a preinit_array (b/25751302) or from another
  108. // constructor called before the libc one (b/68046352). __progname is
  109. // initialized after the other globals, so we can check its value to know if
  110. // calling getauxval is safe.
  111. extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
  112. inline bool areBionicGlobalsInitialized() {
  113. return !SANITIZER_ANDROID || (&__progname && __progname);
  114. }
  115. bool hasHardwareCRC32() {
  116. #if SANITIZER_FUCHSIA
  117. u32 HWCap;
  118. zx_status_t Status = zx_system_get_features(ZX_FEATURE_KIND_CPU, &HWCap);
  119. if (Status != ZX_OK || (HWCap & ZX_ARM64_FEATURE_ISA_CRC32) == 0)
  120. return false;
  121. return true;
  122. #else
  123. if (&getauxval && areBionicGlobalsInitialized())
  124. return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
  125. return hasHardwareCRC32ARMPosix();
  126. #endif // SANITIZER_FUCHSIA
  127. }
  128. #else
  129. bool hasHardwareCRC32() { return false; }
  130. #endif // defined(__x86_64__) || defined(__i386__)
  131. } // namespace __scudo