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