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_POSIX 21 # include "sanitizer_common/sanitizer_posix.h" 22 # include <fcntl.h> 23 # endif 24 #endif 25 26 #include <stdarg.h> 27 28 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less 29 // complicated string formatting code. The following is a 30 // temporary workaround to be able to use __sanitizer::VSNPrintf. 31 namespace __sanitizer { 32 33 extern int VSNPrintf(char *buff, int buff_length, const char *format, 34 va_list args); 35 36 } // namespace __sanitizer 37 38 namespace __scudo { 39 40 FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) { 41 // Our messages are tiny, 256 characters is more than enough. 42 char Message[256]; 43 va_list Args; 44 va_start(Args, Format); 45 VSNPrintf(Message, sizeof(Message), Format, Args); 46 va_end(Args); 47 RawWrite(Message); 48 Die(); 49 } 50 51 #if defined(__x86_64__) || defined(__i386__) 52 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID. 53 // CRC32 requires the SSE 4.2 instruction set. 54 # ifndef bit_SSE4_2 55 # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. 56 # endif 57 bool hasHardwareCRC32() { 58 u32 Eax, Ebx, Ecx, Edx; 59 __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx); 60 const bool IsIntel = (Ebx == signature_INTEL_ebx) && 61 (Edx == signature_INTEL_edx) && 62 (Ecx == signature_INTEL_ecx); 63 const bool IsAMD = (Ebx == signature_AMD_ebx) && 64 (Edx == signature_AMD_edx) && 65 (Ecx == signature_AMD_ecx); 66 if (!IsIntel && !IsAMD) 67 return false; 68 __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx); 69 return !!(Ecx & bit_SSE4_2); 70 } 71 #elif defined(__arm__) || defined(__aarch64__) 72 // For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP 73 // auxiliary vector. 74 # ifndef AT_HWCAP 75 # define AT_HWCAP 16 76 # endif 77 # ifndef HWCAP_CRC32 78 # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms. 79 # endif 80 # if SANITIZER_POSIX 81 bool hasHardwareCRC32ARMPosix() { 82 uptr F = internal_open("/proc/self/auxv", O_RDONLY); 83 if (internal_iserror(F)) 84 return false; 85 struct { uptr Tag; uptr Value; } Entry = { 0, 0 }; 86 for (;;) { 87 uptr N = internal_read(F, &Entry, sizeof(Entry)); 88 if (internal_iserror(N) || N != sizeof(Entry) || 89 (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP) 90 break; 91 } 92 internal_close(F); 93 return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0); 94 } 95 # else 96 bool hasHardwareCRC32ARMPosix() { return false; } 97 # endif // SANITIZER_POSIX 98 99 // Bionic doesn't initialize its globals early enough. This causes issues when 100 // trying to access them from a preinit_array (b/25751302) or from another 101 // constructor called before the libc one (b/68046352). __progname is 102 // initialized after the other globals, so we can check its value to know if 103 // calling getauxval is safe. 104 extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname; 105 INLINE bool areBionicGlobalsInitialized() { 106 return !SANITIZER_ANDROID || (&__progname && __progname); 107 } 108 109 bool hasHardwareCRC32() { 110 if (&getauxval && areBionicGlobalsInitialized()) 111 return !!(getauxval(AT_HWCAP) & HWCAP_CRC32); 112 return hasHardwareCRC32ARMPosix(); 113 } 114 #else 115 bool hasHardwareCRC32() { return false; } 116 #endif // defined(__x86_64__) || defined(__i386__) 117 118 } // namespace __scudo 119