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